Block-1




Introduction to Angular 2

Angular 1 was released in October 2010, and by far the most popular JavaScript framework available for creating web applications. Many developers are already using Angular 1, so the obvious question that comes to our mind is why should we use Angular 2.

Angular 2 is not a simple upgrade from angular 1. Angular 2 is completely rewritten, so it has lot of improvements when compared with Angular 1. Let's look at a few of these improvements.



Performance : From a performance standpoint, Angular 2 has faster initial loads, change detection, and improved rendering time. Not just performance, we also have improved modularity, Dependency injection and testability. According to angular conference meetup, Angular 2 is 5 times faster compared to AngularJS 1.



Mobile Support : Angular 1 was not built for mobile devices. It is possible to run Angular 1 on mobile but we will have to use other frameworks. Angular 2 on the other hand is designed from the ground up with mobile support. Mobile device features and limitations like touch interfaces, limited screen real estate, and mobile hardware have all been considered in Angular 2. So with Angular 2 we can build a single application that works across mobile and desktop devices.

Component Based Development : Component based web development is the future of web development. In Angular 2, "everything is a component". Components are the building blocks of an Angular application. The advantage of the component-based approach is that, it facilitates greater code reuse. From unit testing standpoint, the use of components make Angular2 more testable. We will discuss what a component is and how to build components with examples in detail, in our upcoming videos.

More language choices : There are several languages that we can use to develop Angular applications. To name a few, we have
1. ECMAScript 5
2. ECMAScript 6 (also called ES 2015)
3. TypeScript etc.

Besides these 3 languages we can also use Dart, PureScript, Elm, etc, but among all these, TypeScript is the most popular language. 

Angular 2 itself, is built using TypeScript. TypeScript has great support of ECMAScript 6 standard. So the obvious questions that come to our mind at this point are 
1. What is ECMAScript 
2. Wha is Type Script

What is ECMAScript : The JavaScript language standard is officially called ECMAScript. Over the past several years many versions of ECMAScript were released starting with ECMAScript version 1 all the way till ECMAScript version 7.

Most of the modern browsers available today support ECMAScript 5. The browser support for ECMAScript 6 is still incomplete. However, using a process called Transpilation, ECMAScript 6 can be converted to ECMAScript 5 which is supported by all the modern browsers. ECMAScript 6 is officially known as ECMAScript 2015. ECMAScript 2015 introduced several new features like classes, modules, arrow functions etc.

If you are interested in reading more about the ECMAScript standard and what these different versions of ECMAScript have to offer, please refer to the the following Wikipedia article.
https://en.wikipedia.org/wiki/ECMAScript

Wha is Type Script : TypeScript is a free and open-source programming language developed by Microsoft. It is a superset of JavaScript and compiles to JavaScript through a process called transpilation. Using TypeScript to build angular applications provides several benefits.
1. Intellisense 
2. Autocompletion
3. Code navigation
4. Advanced refactoring
5. Strong Typing
6. Supports ES 2015 (also called ES 6) features like classes, interfaces and inheritance. If you have any experience with object oriented programming languages like C# and Java, learning TypeScript is easy.

Because of all these benefits writing, maintaining and refactoring applications can be an enjoyable experience. So obviously TypeScript has become the number one choice of many developers for developing Angular applications.

For this course we will be using Visual Studio as the code editor. Besides Visual Studio, TypeScript is supported by several other editors like
1. Visual Studio Code
2. Eclipse
3. WebStorm
4. Atom
5. Sublime Text etc.

So you can use any favourite editor of your choice to build Angular 2 applications using TypeScript.

In our next video, we will discuss Setting up Angular 2 in Visual Studio.

Video Link


Setting up Angular 2 in Visual Studio


Suggested Videos

Part 1 - Introduction to Angular 2 | Text | Slides

In this video we will discuss how to set up Angular 2 in Visual Studio.

Step 1 : The first step is to install Node.js and npm. It is recommended that you have node version 4.6.x or greater and npm 3.x.x or greater. To check the versions that you have on your machine type the following commands in a command window.
node -v 
npm -v



You can get the latest version of Node.js from the following website. Click on the correct download link depending on the Operating System you have.
https://nodejs.org/en/download/

I have Windows 64 bit Operating system, so I have downloaded 64 - bit windows installer.



To find out if you have 32 - bit or 64 - bit operating system 
  1. Click the Start icon , 
  2. Type "System" in the Start Search box, and then click System Information in the Programs list.
  3. Select "System Summary" 
  4. In the right pane if 
    • System type is x64-based PC, then you have 64-bit operating system
    • System type is x86-based PC, then you have 32-bit operating system
Step 2 : Make sure you have Visual Studio 2015 Update 3 installed. To check the version of Visual Studio you have click on the "Help" menu and then select "About Microsoft Visual Studio". The following are the download links if you don't have Visual Studio 2015 Update 3.

Visual Studio Enterprise 2015 - Update 3
Visual Studio Professional 2015 - Update 3
Visual Studio Community 2015 - Update 3

how to check version of visual studio

Step 3 : Configure environment settings for node and npm in Visual Studio
  1. In Visual Studio click on Tools - Options.
  2. In the "Options" window, expand "Projects and Solutions" and select "External Web Tools"
  3. In the right pane, move the global $(PATH) entry to be above the internal path $(DevEnvDir) entries. This tells Visual Studio to look for external tools (like npm) in the global path before the internal path.
  4. Click "OK" to close the "Options" window and then restart Visual Stduio for the changes to take effect
visual studio external web tools

Step 4 :  Install TypeScript for Visual Studio 2015
  1. To develop Angular applications you need TypeScript 2.2.0 or later
  2. To check the version of TypeScript, clik on the "Help" menu in Visual Studio and select "About Microsoft Visual Studio"
    how to check version of typescript

  3. Download and install the latest version of TypeScript for Visual Studio 2015 from the following URLhttps://www.microsoft.com/en-us/download/details.aspx?id=48593
  4. After installing TypeScript, the installation wizard prompts you to restart Visual Studio. So, please restart Visual Studio for the changes to take effect.
Step 5 : Create Empty ASP.NET Web Application project
  1. Run Visual Studio as Administrator
  2. Click on File - New Project
  3. Select "Web" under "Visual C#". From the right pane select "ASP.NET Web Application"
  4. Name the project "Angular2Demo"
  5. On the next screen, select "Empty" template and click "OK"
Step 6 : Download the "Quick Start Files" from the Angular web site using the link below. Extract the contents of the downloaded .ZIP folder.
https://github.com/angular/quickstart

Step 7 : Copy the required "Starter files" to the web application project

We do not need all the starter files that we downloaded. As you can see from the image below, we need 4 folders/files
  • src folder and it's contents
  • bs-config.json
  • package.json
  • tslint.json
angular 2 setup in visual studio

Copy the above files/folders and paste them in the root directory of "Angular2Demo" web application project. Now click "Show All File" icon in "Solution Explorer" and include all the copied files/folders in the project. At this stage your project structure in Visual Studio should be as shown below.

visual studio 2015 angular 2 setup

When including the files in the project if you get a prompt to "Search for Typescript Typings" click "No"
search for typescript typings

Step 8 : Restore the required packages. 
In the "Solution Explorer" right click on "package.json" file and select "Restore Packages" from the context menu. This takes a few minutes to load all the modules. You can see the status in "Visual Studio Output" window. After the restoration is complete, you will see a message "Installing Packages Complete". To see all the installed node modules, click on "Show all Files" icon in Solution Explorer. DO NOT include "node_modules" folder in the project.

installing angular 2 in visual studio

Step 9 : Run the project
  1. In the "RUN" window type "cmd" and press enter
  2. Change the directory in the command prompt to the directory where you have the web application project. I have my web application project in "C:\Angular2Demo\Angular2Demo". So I have typed CD C:\Angular2Demo\Angular2Demo and upon pressing the enter key I am in the root folder.
  3. Type "npm start" and press "Enter" key
    npm start command
  4. This launches the TypeScript compiler (tsc) which compile the application and wait for changes. It also starts the lite-server and launches the browser where you will see the output - Hello Angular.
  5. At this point, open "app.component.ts" file from "Solution Explorer". This file is present in "app" folder in "src" folder.
  6. Change "name" value from "Angular" to "Angular 2!" and you will see the changes reflected on the web page automatically.
At the moment we do not have the capability to run the project by pressing F5 or CTRL + F5. We will discuss how to do this in our next video.

Video Link


Run angular 2 app using f5 from visual studio


Suggested Videos

Part 1 - Introduction to Angular 2 | Text | Slides
Part 2 - Setting up Angular 2 in Visual Studio | Text | Slides

In this video we will discuss how to run angular 2 application from visual studio using F5 or CTRL + F5.

This is continuation to Part 2. Please watch Part 2 from Angular 2 tutorial before proceeding.



At the moment, if we run the application from Visual Studio, using F5 or CTRL+F5, we get the message "Loading AppComponent content here ..." but nothing happens beyond that. To be able to run the application using F5 or CTRL+F5 we need to make the following changes.



1. Launch browser developers tools by pressing F12. Notice we have "404 Not Found" errors for the following files.
  • styles.css
  • systemjs.config.js
  • main.js
angular 2 loading appcomponent content here

All these files are present in "src" folder. So to fix these "404 Not Found" errors, in index.html file, change <base href="/"> to <base href="/src/">

2. Save the changes and reload the page. At this point we get another set of "404 Not Found" errors for the following files.
  • shim.min.js
  • zone.js
  • system.src.js
angular 2 node_modules 404

<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>

To fix these errors, in index.html change the above script references as shown below. Notice, we have included "/" just before node_modules

<script src="/node_modules/core-js/client/shim.min.js"></script>
<script src="/node_modules/zone.js/dist/zone.js"></script>
<script src="/node_modules/systemjs/dist/system.src.js"></script>

Also in systemjs.config.js file, CHANGE
'npm:': 'node_modules/'  TO  'npm:''/node_modules/'

At this point reload the page and you will see "Hello Angular" message without any errors.

One important point to keep in mind is that, now we will not be able to run the application using "npm start" command.

We still have one more issue. Let us first understand the issue.
1. Expand "app" folder. This folder is inside "src" folder
2. Open "app.component.ts" file 
3. Set name="Angular 2!" from name="Angular"
4. Save the changes and reload the web page 
5. Notice, we do not see the changes on the web page
6. However, if we run the application by pressing F5 or CTRL+F5 from visual studio we see the changes in the browser.

So what is the issue?
TypeScript is not complied to JavaScript when we save the file and this the reason we do not see the changes in the browser. However, when we run the application by pressing F5 or CTRL+F5 from visual studio TypeScript is compiled to JavaScript and we see the changes.

If you want Visual Studio to compile TypeScript to JavaScript when the changes are saved, we need to turn this feature "ON" by including the following setting in tsconfig.json file. You will find this file in "src" folder. Notice we have set "compileOnSave" to true. With this change tsconfig.json file looks as shown below.
{
  "compileOnSave": true,
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [ "es2015", "dom" ],
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}

At this point TypeScript is automatically compiled to JavaScript when the file is saved, so the changes are reflected in the browser when the page is reloaded.

At the moment, we are using Visual Studio built-in IIS express server. In a later video in this course we will discuss how to use full blown IIS instead of Visual Studi built-in IIS express.

Should I learn AngularJS1 before learning Angular 2?
NO, Angular 2 is completely rewritten and very different from AngularJS1, so there is no need to learn AngularJS 1 before learning Angular 2.


Video Link


Run angular 2 app using f5 from visual studio


Suggested Videos

Part 1 - Introduction to Angular 2 | Text | Slides
Part 2 - Setting up Angular 2 in Visual Studio | Text | Slides

In this video we will discuss how to run angular 2 application from visual studio using F5 or CTRL + F5.

This is continuation to Part 2. Please watch Part 2 from Angular 2 tutorial before proceeding.



At the moment, if we run the application from Visual Studio, using F5 or CTRL+F5, we get the message "Loading AppComponent content here ..." but nothing happens beyond that. To be able to run the application using F5 or CTRL+F5 we need to make the following changes.



1. Launch browser developers tools by pressing F12. Notice we have "404 Not Found" errors for the following files.
  • styles.css
  • systemjs.config.js
  • main.js
angular 2 loading appcomponent content here

All these files are present in "src" folder. So to fix these "404 Not Found" errors, in index.html file, change <base href="/"> to <base href="/src/">

2. Save the changes and reload the page. At this point we get another set of "404 Not Found" errors for the following files.
  • shim.min.js
  • zone.js
  • system.src.js
angular 2 node_modules 404

<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>

To fix these errors, in index.html change the above script references as shown below. Notice, we have included "/" just before node_modules

<script src="/node_modules/core-js/client/shim.min.js"></script>
<script src="/node_modules/zone.js/dist/zone.js"></script>
<script src="/node_modules/systemjs/dist/system.src.js"></script>

Also in systemjs.config.js file, CHANGE
'npm:': 'node_modules/'  TO  'npm:''/node_modules/'

At this point reload the page and you will see "Hello Angular" message without any errors.

One important point to keep in mind is that, now we will not be able to run the application using "npm start" command.

We still have one more issue. Let us first understand the issue.
1. Expand "app" folder. This folder is inside "src" folder
2. Open "app.component.ts" file 
3. Set name="Angular 2!" from name="Angular"
4. Save the changes and reload the web page 
5. Notice, we do not see the changes on the web page
6. However, if we run the application by pressing F5 or CTRL+F5 from visual studio we see the changes in the browser.

So what is the issue?
TypeScript is not complied to JavaScript when we save the file and this the reason we do not see the changes in the browser. However, when we run the application by pressing F5 or CTRL+F5 from visual studio TypeScript is compiled to JavaScript and we see the changes.

If you want Visual Studio to compile TypeScript to JavaScript when the changes are saved, we need to turn this feature "ON" by including the following setting in tsconfig.json file. You will find this file in "src" folder. Notice we have set "compileOnSave" to true. With this change tsconfig.json file looks as shown below.
{
  "compileOnSave": true,
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [ "es2015", "dom" ],
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}

At this point TypeScript is automatically compiled to JavaScript when the file is saved, so the changes are reflected in the browser when the page is reloaded.

At the moment, we are using Visual Studio built-in IIS express server. In a later video in this course we will discuss how to use full blown IIS instead of Visual Studi built-in IIS express.

Should I learn AngularJS1 before learning Angular 2?
NO, Angular 2 is completely rewritten and very different from AngularJS1, so there is no need to learn AngularJS 1 before learning Angular 2.


Video Link


Angular 2 components


Suggested Videos

Part 1 - Introduction to Angular 2 | Text | Slides
Part 2 - Setting up Angular 2 in Visual Studio | Text | Slides
Part 3 - Run angular 2 app using f5 from visual studio | Text | Slides

In this video tutorial we will discuss - What is a component in Angular 2

In Part 1 of Angular 2 tutorial, we discussed that everything in Angular 2 is a component i.e components are the basic building blocks of an Angular application. 



What is a component in Angular 2
A component in Angular is a class with a template and a decorator. So in simple terms a component in Angular is composed of these 3 things
  • Template - Defines the user interface. Contains the HTML, directives and bindings.
  • Class - Contains the code required for template. Just like a class in any object oriented programming language like C# or Java, a class in angular can contain methods and properties. Properties contain the data that we want to display in the view template and methods contain the logic for the view. We use TypeScript to create the class.
  • Decorator - We use the Component decorator provided by Angular to add metadata to the class. A class becomes an Angular component, when it is decorated with the Component decorator.


Component Example : In Part 2 of Angular 2 tutorial, we have downloaded quick start files from the Angular Website. One of the files in these quick start files, is the app.component.ts file. You can find this file in the "app" folder. This file contain a component. The name of the component is AppComponent. The AppComponent is the root component of the application. I have commented the code in the following example and it should be self-explanatory. If it's not, please watch the video by clicking here.

// Component decorator is provided by the Angular core library, so we
// have to import it before using it. The import keyword is similar to
// using keyword in C#. Any exported member can be imported using import
// keyowrd.
import { Component } from '@angular/core';

// The class is decorated with Component decorator which adds metadata
// to the class. We use the @ symbol to apply a decorator to the class
// Applying a decorator on a class is similar to applying an attribute
// to a class in C# or other programming languages. Component is just
// one of the deveral built-in decorators provided by angular. We will
// discuss the other decorators provided by angular in upcoming videos
@Component({
    // component has several properties. Here we are using just 2. For
    // the full list of properties refer to the following URL
    // https://angular.io/docs/ts/latest/api/core/index/Component-decorator.html
    // To use this component on any HTML page we specify the selector
    // This selector becomes the directive <my-app> on the HTML page
    // At run time, the directive <my-app> is replaced by the template
    // HTML specified below
    selector: 'my-app',
    // The template contains the HTML to render. Notice in the HTML
    // we have a data-binding expression specified by double curly
    // braces. We have a defualt value "Angular" assigned to "name"
    // property in the AppComponent class. This will be used at runtime
    // inplace of the data-binding expression
    template: `<h1>Hello {{name}}</h1>`,
})
// export keyword allows this class to be exported, so other components 
// in the application can import and use it if required
export class AppComponent {
    // name is a property and the data type is string and
    // has a default value "angular"
    name: string = 'Angular';
}

Notice in the index.html page, we have used the AppComponent using the directive <my-app>. At runtime <my-app> directive is replaced with the HTML we specified using the selector property in the component decorator.

<!DOCTYPE html>
<html>
<head>
    <title>Angular QuickStart</title>
    <base href="/src/">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">

    <!-- Polyfill(s) for older browsers -->
    <script src="/node_modules/core-js/client/shim.min.js"></script>
    <script src="/node_modules/zone.js/dist/zone.js"></script>
    <script src="/node_modules/systemjs/dist/system.src.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
        System.import('main.js').catch(function (err) { console.error(err); });
    </script>
</head>
<body>
    <my-app>Loading AppComponent content here ...</my-app>
</body>
</html>

When we build the project in Visual Studio TypeScript is compiled to JavaScript which the browser understands and renders. Our TypeScript code for this component is present in app.component.ts file. Notice a corresponding app.component.js is file is generated on build. To see the generated .js file click on show-all-files icon in solution explorer. Besides .js files, there are several other files. We will discuss what these files are, their purpose and how angular application bootstraps itself using these files in our upcoming videos. 

Video Link


Angular template vs templateurl


Suggested Videos

Part 2 - Setting up Angular 2 in Visual Studio | Text | Slides
Part 3 - Run angular 2 app using f5 from visual studio | Text | Slides
Part 4 - Angular 2 components | Text | Slides

In this video we will discuss template and templateurl properties of the Component decorator. This is continuation to Part 4, please watch Part 4 from Angular 2 tutorial before proceeding.



In Part 4, we have used an inline view template. Notice the code we have implemented in app.component.ts file. We have embedded the view template inline in the .ts file.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<h1>Hello {{name }}</h1>`
})
export class AppComponent {
    name: string = 'Angular';
}



The view template is inline in a pair of backtick characters. The first question that comes to our mind is can't we include the HTML in a pair of single or double quotes. The answer is "YES" we can as long as the HTML is in a single line. So this means the above code can be rewritten using a pair of single quotes as shown below.

template: '<h1>Hello {{name }}</h1>'

We can also replace the pair of single quotes with a pair of double quotes as shown below, and the application still continues to work exactly the same way as before.

template: "<h1>Hello {{name }}</h1>"

The obvious next question that comes to our mind is when should we use backticks instead of single or doublequotes
If you have the HTML in more than one line, then you have to use backticks instead of single or double quotes as shown below. If you use single or double quotes instead of backticks you will get an error.

template: `<h1>
                      Hello {{name }}
                </h1>`

Instead of using an inline view template, you can have it in a separate HTML file. Here are the steps to have the view template in a separate HTML file

Step 1 : Right click on the "app" folder and add a new HTML file. Name it "app.component.html".

Step 2 : Include the following HTML in "app.component.html"

<h1>
    Hello {{name}}
</h1>

Step 3 : In "app.component.ts", reference the external view template using templateUrl property as shown below. Notice instead of the "template" property we are using "templateUrl" property. Please note that templateUrl path is relative to index.html

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    templateUrl: 'app/app.component.html'
})
export class AppComponent {
    name: string = "Angular";
}

What are the differences between template and templateUrl properties and when to use one over the other
Angular2 recommends to extract templates into a separate file, if the view template is longer than 3 lines. Let's understand why is it better to extract a view template into a seprate file, if it is longer than 3 lines.

With an inline template 
  1. We loose Visual Studio editor intellisense, code-completion and formatting features.
  2. TypeScript code is not easier to read and understand when it is mixed with the inline template HTML.
With an external view template
  1. We have Visual Studio editor intellisense, code-completion and formatting features and 
  2. Not only the code in "app.component.ts" is clean, it is also easier to read and understand
Video Link


Angular 2 nested components


Suggested Videos

Part 3 - Run angular 2 app using f5 from visual studio | Text | Slides
Part 4 - Angular 2 components | Text | Slides
Part 5 - Angular template vs templateurl | Text | Slides

In this video we will discuss nesting angular components i.e including a component inside another component. This is continuation to Part 5, please watch Part 5 from Angular 2 tutorial before proceeding.

As we already know Angular 2 is all about components. A component in Angular allows us to create a reusable UI widget. A component can be used by any other component. Let's look at a simple example of nesting a component inside another component.



Here is what we want to do. Create a page that displays Employee details as shown below.
Angular 2 nested components



As you can see from the image below we want to create 2 components

  • AppComponent - This component is the root component and displays just the page header
  • EmployeeComponent - This component is the child component and displays the Employee details table. This child component will be nested inside the root AppComponent
angular 2 component in another component

Step 1 : Right click on the "App" folder and add a new folder. Name it "employee". We will create our EmployeeComponent in this folder.

Step 2 : Right click on the "employee" folder and add a new HTML page. Name it employee.component.html. Copy and paste the following HTML.

<table>
    <tr>
        <td>First Name</td>
        <td>{{firstName}}</td>
    </tr>
    <tr>
        <td>Last Name</td>
        <td>{{lastName}}</td>
    </tr>
    <tr>
        <td>Gender</td>
        <td>{{gender}}</td>
    </tr>
    <tr>
        <td>Age</td>
        <td>{{age}}</td>
    </tr>
</table>

Step 3 : Right click on the "employee" folder and add a new TypeScript file. Name it employee.component.ts. Copy and paste the following code in it. At this point we have our child component EmployeeComponent created. Next let's create the root component - AppComponent.

import { Component } from '@angular/core';

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html'
})
export class EmployeeComponent {
    firstName: string = 'Tom';
    lastName: string = 'Hopkins';
    gender: string = 'Male';
    age: number = 20;
}

Step 4 : We are going to use the root component to just display the page header. So in "app.component.ts" file, include the following code. Notice, since the View Template HTML is just 3 lines we have used an inline template instead of an external template. Angular2 recommends to extract templates into a separate file, if the view template is longer than 3 lines.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<div>
                    <h1>{{pageHeader}}</h1>
               </div>`
})
export class AppComponent {
    pageHeader: string = 'Employee Details';
}

At this point if we run the application, we only see the page header - "Employee Details", but not the table which has the employee details. To be able to display employee details table along with the page header, we will have to nest EmployeeComponent inside AppComponent. There are 2 simple steps to achieve this.

Step 1 : In "app.module.ts" file we need to do 2 things as shown below.
  • Import EmployeeComponent 
  • Add EmployeeComponent to the declarations array
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { EmployeeComponent } from './employee/employee.component';

@NgModule({
    imports: [BrowserModule],
    declarations: [AppComponent, EmployeeComponent],
    bootstrap: [AppComponent]
})

export class AppModule { }

What is AppModule
AppModule is the root module which bootstraps and launches the angular application. You can name it anything you want, but by convention it is named AppModule.

It imports 2 system modules - BrowserModule and NgModule 
  • BrowserModule - Every application that runs in a browser needs this module. In a later video in this course we will discuss NgIf and NgFor directives which are also provided by this module.
  • NgModule - @component decorator adds metadata to an angular component class, similarly @NgModule decorator adds metadata to the angular module class.
In Part 4 of this tutorial, we discussed that if a class is decorated @component decorator then that class becomes an angular component. Similarly if a a class is decorated with @NgModule decorator then that class becomes an angular module.

Properties of the @NgModule decorator
  • imports - Imports the BrowserModule required for an angular application to run in a web browser
  • declarations - Contains the components registered with this module. In our case we have two - AppComponent and EmployeeComponent
  • bootstrap - Contains the root component that Angular creates and inserts into the index.html host web page
Step 2 : In "app.component.ts" file include "my-employee" as a directive. Remember in "employee.component.ts" file we used "my-employee" as a selector.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<div>
                    <h1>{{pageHeader}}</h1>
                    <my-employee></my-employee>
                </div>`
})
export class AppComponent {
    pageHeader: string = 'Employee Details';
}

Run the application and you will see both page header and the employee details table. The employee details table is not styled very well. To style the table, include the following styles for <td> and <table> elements in styles.css file.

table {
    color: #369;
    font-family: Arial, Helvetica, sans-serif;
    font-size:large;
    border-collapse: collapse;
}

td {
    border: 1px solid black;
}

Run the application and you will now see the employee details table with the specified styles applied. At this point, launch browser developers tools and click on the "Elements" tab and notice <my-app> and <my-employee> directives in the rendered HTML.

angular 2 nested components example

Video Link


Styling angular 2 components

Suggested Videos
Part 4 - Angular 2 components | Text | Slides
Part 5 - Angular template vs templateurl | Text | Slides
Part 6 - Angular 2 nested components | Text | Slides

In this video we will discuss the different options available to apply styles to Angular Components. This is continuation to Part 6. Please watch Part 6 from Angular 2 tutorial before proceeding.



In our previous video we have built "employee" component which displays employee details in a table as shown below.

styling angular components



employee.component.ts 

import { Component } from '@angular/core';

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html'
})
export class EmployeeComponent {
    firstName: string = 'Tom';
    lastName: string = 'Hopkins';
    gender: string = 'Male';
    age: number = 20;
}

employee.component.html

<table>
    <tr>
        <td>First Name</td>
        <td>{{firstName}}</td>
    </tr>
    <tr>
        <td>Last Name</td>
        <td>{{lastName}}</td>
    </tr>
    <tr>
        <td>Gender</td>
        <td>{{gender}}</td>
    </tr>
    <tr>
        <td>Age</td>
        <td>{{age}}</td>
    </tr>
</table>

The following are the different options available to style this "employee component"

Option 1: Specify the following <table> and <td> styles in external stylesheet - styles.css

table {
    color: #369;
    font-family: Arial, Helvetica, sans-serif;
    font-size: large;
    border-collapse: collapse;
}

td {
    border: 1px solid black;
}

Advantages : 
  1. Visual Studio editor features (Intellisense, Code completion & formatting) are available.
  2. Application maintenance is also easy as we only have to change the styles in one place if we need to change them for any reason.
Disadvantages : 
  1. The Stylesheet that contains the styles must be referenced for the component to be reused.
  2. Since styles.css is referenced in index.html page, these styles may affect the table and td elements in other components, and you may or may not want this behaviour.
Option 2 : Specify the styles inline in the component HTML file as shown below.

<table style="color: #369;font-family: Arial, Helvetica, sans-serif;
              font-size:large;border-collapse: collapse;">
    <tr>
        <td style="border: 1px solid black;">First Name</td>
        <td style="border: 1px solid black;">{{firstName}}</td>
    </tr>
    <tr>
        <td style="border: 1px solid black;">Last Name</td>
        <td style="border: 1px solid black;">{{lastName}}</td>
    </tr>
    <tr>
        <td style="border: 1px solid black;">Gender</td>
        <td style="border: 1px solid black;">{{gender}}</td>
    </tr>
    <tr>
        <td style="border: 1px solid black;">Age</td>
        <td style="border: 1px solid black;">{{age}}</td>
    </tr>
</table>

Advantages : 
  1. Visual Studio editor features (Intellisense, Code completion & formatting) are available.
  2. Component can be easily reused as the styles are defined inline
  3. Styles specified using this approach are local to the component and don't collide with styles used elsewhere in the application.
Disadvantages : 
  1. Application maintenance is difficult. For example, if we want to change the <td> border colour to red we have to change it in several places.
Option 3 : Specify the styles in the component html file using <style> tag as shown below

<style>
    table {
        color: #369;
        font-family: Arial, Helvetica, sans-serif;
        font-size: large;
        border-collapse: collapse;
    }

    td {
        border: 1px solid black;
    }
</style>
<table>
    <tr>
        <td>First Name</td>
        <td>{{firstName}}</td>
    </tr>
    <tr>
        <td>Last Name</td>
        <td>{{lastName}}</td>
    </tr>
    <tr>
        <td>Gender</td>
        <td>{{gender}}</td>
    </tr>
    <tr>
        <td>Age</td>
        <td>{{age}}</td>
    </tr>
</table>

Advantages : 
  1. Component can be easily reused as the styles are defined inline with in the component itself
  2. Application maintenance is also easy as we only have to change the styles in one place
  3. Visual Studio editor features (Intellisense, Code completion & formatting) are available
  4. Styles specified using this approach are local to the component and don't collide with styles used elsewhere in the application.
Option 4 : Specify the styles in the component TypeScript file using the @component decorator styles property as shown below. Notice the styles property takes an array of strings containing your styles.

import { Component } from '@angular/core';

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html',
    styles: ['table { color: #369; font-family: Arial, Helvetica, sans-serif; font-size: large; border-collapse: collapse;}', 'td {border: 1px solid black; }']
})
export class EmployeeComponent {
    firstName: string = 'Tom';
    lastName: string = 'Hopkins';
    gender: string = 'Male';
    age: number = 20;
}

Advantages : 
  1. Component can be easily reused as the styles are defined inline with in the component itself
  2. Application maintenance is also easy as we only have to change the styles in one place for this component if we need to change them for any reason.
  3. Styles specified using this approach are local to the component and don't collide with styles used elsewhere in the application.
Disadvantages :
  1. Visual Studio editor features (Intellisense, Code completion & formatting) are not available.
Option 5 : Specify the styles using the @component decorator styleUrls property. The styleUrls property is an array of strings containing stylesheet URLs. 

Step 1 : Right click on the "employee" folder and add a new StyleSheet. Name it employee.component.css

Step 2 : Copy and paste the following styles for <table> and <td> elements in employee.component.css

table {
    color: #369;
    font-family: Arial, Helvetica, sans-serif;
    font-size: large;
    border-collapse: collapse;
}

td {
    border: 1px solid black;
}

Step 3 : In employee.component.ts file reference employee.component.css stylesheet using styleUrls property as shown below. Please note, the stylesheet path is relative to index.html file.

import { Component } from '@angular/core';

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html',
    styleUrls: ['app/employee/employee.component.css']
})
export class EmployeeComponent {
    firstName: string = 'Tom';
    lastName: string = 'Hopkins';
    gender: string = 'Male';
    age: number = 20;
}

Advantages : 
  1. Component can be easily reused as both the stylesheet itself and it's path are included with in the component
  2. Application maintenance is also easy as we only have to change the styles in one place
  3. Visual Studio editor features (Intellisense, Code completion & formatting) are available
  4. Styles specified using this approach are local to the component and don't collide with styles used elsewhere in the application.
Video Link


Angular interpolation

Suggested Videos
Part 5 - Angular template vs templateurl | Text | Slides
Part 6 - Angular 2 nested components | Text | Slides
Part 7 - Styling angular 2 components | Text | Slides

In this video we will discuss the concept of Interpolation in Angular.

Interpolation is all about data binding. In Angular data-binding can be broadly classified into 3 categories
Data Binding Description
One way data-binding From Component to View Template
One way data-binding From View Template to Component
Two way data-binding From Component to View Template & From View template to Component



In this video, we will discuss the first one way data-binding i.e From Component to View Template. We achieve this using interpolation. We will discuss the rest of the 2 data-binding techniques in our upcoming videos.

One way data-binding - From Component to View Template : To display read-only data on a view template we use one-way data binding technique interpolation. With interpolation, we place the component property name in the view template, enclosed in double curly braces: {{propertyName}}.



In the following example, Angular pulls the value of the firstName property from the component and inserts it between the opening and closing <h1> element.


import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <h1>{{ firstName }}</h1>
              `
})
export class AppComponent {
    firstName: string = 'Tom';
}

Output : 
angular interpolation example

It is also possible to concatenate a hard-coded string with the property value
<h1>{{'Name = ' + firstName}}</h1>

The above expression displayes "Name = Tom" in the browser.

You can specify any valid expression in double curly braces. For example you can have 
<h1>{{ 10 + 20 + 30 }}</h1>

The above expression evaluates to 60

The expression that is enclosed in double curly braces is commonly called as Template Expression. This template expression can also be a ternary operator as shown in the example below. Since firstName property has a value 'Tom', we see it in the browser.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <h1>{{firstName ? firstName : 'No name specified'}}</h1>
              `
})
export class AppComponent {
    firstName: string = 'Tom';
}

If we set firstName = null as shown below. The value 'No name specified' is displayed in the browser
firstName: string = null;

You can also use interpolation to set <img> src as shown in the example below.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<div>
                    <h1>{{pageHeader}}</h1>
                    <img src='{{imagePath}}'/>
                </div>`
})
export class AppComponent {
    pageHeader: string = 'Employee Details';
    imagePath: string = 'http://pragimtech.com/images/logo.jpg';
}

Output : 
angularjs attribute interpolation

We can also call class methods using interpolation as shown below.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<div>
                    <h1>{{'Full Name = ' + getFullName()}}</h1>
                </div>`
})
export class AppComponent {
    firstName: string = 'Tom';
    lastName: string = 'Hopkins';

    getFullName(): string {
        return this.firstName + ' ' + this.lastName;
    }
}

Output : Full Name = Tom Hopkins

Video Link


Property binding in Angular 2

Suggested Videos
Part 6 - Angular 2 nested components | Text | Slides
Part 7 - Styling angular 2 components | Text | Slides
Part 8 - Angular interpolation | Text | Slides

In this video we will discuss Property binding in Angular with examples. 

In Part 8, we discussed we can use interpolation to bind component class properties to view template. Another option to achieve exactly the same thing is by using Property binding.



In our previous video we have bound imagePath property of the component class to <img> element src property using interpolation as shown below.
<img src='{{imagePath}}'/>

We can rerwrite the above example, using property binding as shown below. Notice the <img> element src property is in a pair of square brackets, and the component class property is in quotes.
<img [src]='imagePath'/>



Both Interpolation and Property binding flows a value in one direction, i.e from a component's data property into a target element property.

What is the difference between Interpolation and Property binding
Interpolation is a special syntax that Angular converts into a property binding. 

Interpolation is just a convenient alternative to property binding. 

In some cases like when we need to concatenate strings we have to use interpolation instead of property binding as shown in the example below.
<img src='http://www.pragimtech.com/{{imagePath}}' />

When setting an element property to a non-string data value, you must use property binding. In the following example, we are disabling a button by binding to the boolean property isDisabled.
<button [disabled]='isDisabled'>Click me</button>

If we use interpolation instead of property binding, the button is always disabled irrespective of isDisabled class property value
<button disabled='{{isDisabled}}'>Click me</button>

Some important points to keep in mind when using Property binding

Remember to enclose the property name with a pair of square brackets. If you omit the brackets, Angular treats the string as a constant and initializes the target property with that string.
<span [innerHTML]='pageHeader'></span>

With Property binding we enclose the element property name in square brackets
<button [disabled]='isDisabled'>Click me</button>

We can also use the alternate syntax with bind- prefix. This is known as canonical form
<button bind-disabled='isDisabled'>Click me</button>

From security standpoint, Angular data binding sanitizes malicious content before displaying it on the browser. Both interpolation and property binding protects us from malicious content.

In the example below we are using interpolation. Notice the malicious usage of <script> tag.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: '<div>{{badHtml}}</div>'
})
export class AppComponent {
    badHtml: string = 'Hello <script>alert("Hacked");</script> World';
}

Angular interpolation sanitizes the malicious content and displays the following in the browser
Hello <script>alert("Hacked");</script> World

In this example below we are using property binding. 
'<div [innerHtml]="badHtml"></div>'

Property binding sanitizes the malicious content slightly differently and we get the following output, but the important point to keep in mind is both the techniques protect us from malicious content and render the content harmlessly.
Hello alert("Hacked"); World

Video Link


html attribute vs dom property

Suggested Videos
Part 7 - Styling angular 2 components | Text | Slides
Part 8 - Angular interpolation | Text | Slides
Part 9 - Property binding in Angular 2 | Text | Slides

In this video we will discuss the difference between HTML attribute and DOM property.


What is DOM
DOM stands for Document Object Model. When a browser loads a web page, the browser creates a Document Object Model of that page.


For example, for the HTML below,
dom property vs attribute

The browser creates a Document Object Model of that page as shown below
difference between html attribute and property

So in simple terms you can think of the DOM as an application programming interface (API) for HTML, and we can use programming languages like JavaScript, or JavaScript frameworks like Angular to access and manipulate the HTML using their corresponding DOM objects.

In other words DOM contains the HTML elements as objects, their properties, methods and events and it is a standard for accessing, modifying, adding or deleting HTML elements.

In the previous 2 videos we discussed interpolation and property binding in Angular.

Interpolation example
<button disabled='{{isDisabled}}'>Click Me</button>

Property binding example
<button [disabled]='isDisabled'>Click Me</button>

If you notice the above 2 examples, it looks like we are binding to the Button's disabled attribute. This is not true. We are actually binding to the disabled property of the button object. Angular data-binding is all about binding to DOM object properties and not HTML element attributes.

What is the difference between HTML element attribute and DOM property
  1. Attributes are defined by HTML, where as properties are defined by the DOM.
  2. Attributes initialize DOM properties. Once the initialization complete, the attributes job is done.
  3. Property values can change, where as attribute values can't.
Let's prove this point - Property values change, but the attribute values don't with an example.

In the example below, we have set the value attribute of the input element to Tom.
<input id='inputId' type='text' value='Tom'>

At this point, run the web page and in the textbox you will see 'Tom' as the value. 

Launch the browser developer tools.

On the 'Console' tab, use the getattribute() method and value property of the input element to get the attribute and property values. Notice at the moment both have the value 'Tom'
html element property vs attribute

Change the value in the textbox to Mary.

Notice now, when we query for the attribute and property values, the attribute value is still Tom but the property value is Mary. So this proves the point - Property values change, where as attribute values don't.
html attribute vs property

So it is important to keep in mind that, 
  1. HTML attributes and the DOM properties are different things.
  2. Angular binding works with properties and events, and not attributes.
  3. The role of attributes is to initialize element properties and their job is done.
Video Link


Angular attribute binding

Suggested Videos
Part 8 - Angular interpolation | Text | Slides
Part 9 - Property binding in Angular 2 | Text | Slides
Part 10 - html attribute vs dom property | Text | Slides

In this video we will discuss Attribute Binding in Angular

In our previous videos we discussed Interpolation and  Property binding that deal with binding Component class properties to HTML element properties and not Attributes. 



However, in some situations we want to be able to bind to HTML element attributes. For example, colspan and aria attributes does not have corresponding DOM properties. So in this case we want to be able to bind to HTML element attributes. 

To make  this happen, Angular provides attribute binding. With attribute binding we can set the value of an attribute directly. Angular team recommends to use Property binding when possible and use attribute binding only when there is no corresponding element property to bind.



Let us understand Attribute Binding in Angular with an example. We want to display Employee Details in a table as shown below.
Angular attribute binding

To achieve this we are going to make use of Employee component we have implemented in Part 6 of Angular 2 tutorial.

In our root component - app.component.ts we have the following code

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <div>
                    <my-employee></my-employee>
                </div>
             `
})
export class AppComponent {
}

Code in employee.component.ts file
import { Component } from '@angular/core';

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html',
    styleUrls: ['app/employee/employee.component.css']
})
export class EmployeeComponent {
    imagePath: string = 'Tom.png';
    firstName: string = 'Tom';
    lastName: string = 'Hopkins';
    gender: string = 'Male';
    age: number = 20;
}


Code in employee.component.css file
table {
    color: #369;
    font-family: Arial, Helvetica, sans-serif;
    font-size: large;
    border-collapse: collapse;
}

td {
    border: 1px solid black;
}
thead{
    border: 1px solid black;
}

Code in employee.component.html file
<table>
    <thead>
        <tr>
            <th colspan="2">
                Employee Details
            </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>First Name</td>
            <td>{{firstName}}</td>
        </tr>
        <tr>
            <td>Last Name</td>
            <td>{{lastName}}</td>
        </tr>
        <tr>
            <td>Gender</td>
            <td>{{gender}}</td>
        </tr>
        <tr>
            <td>Age</td>
            <td>{{age}}</td>
        </tr>
    </tbody>
</table>

Notice at the moment we have hard-coded colspan attribute value to 2 in the HTML. Instead we want to bind to a component class property. So in the employee.component.ts file include 'columnSpan' property as shown below.

export class EmployeeComponent {
    columnSpan: number = 2;
    imagePath: string = 'Tom.png';
    firstName: string = 'Tom';
    lastName: string = 'Hopkins';
    gender: string = 'Male';
    age: number = 20;
}

If we use interpolation to bind columnSpan property of the component class to colspan attribute of the <th> element we get the error - Can't bind to 'colspan' since it isn't a known property of 'th'
<th colspan="{{columnSpan}}">

We get the same error if we use Property Binding
<th [colspan]="columnSpan">

This error is because we do not have a corresponding property in the DOM for colspan attribute. To fix this we have to use attribute-binding in Angular, which sets the colspan attribute. To tell angular framework that we are setting an attribute value we have to prefix the attribute name with attr and a DOT as shown below.
<th [attr.colspan]="columnSpan">

The same is true when using interpolation
<th attr.colspan="{{columnSpan}}">

Video Link


Class binding in angular 2

Suggested Videos
Part 9 - Property binding in Angular 2 | Text | Slides
Part 10 - html attribute vs dom property | Text | Slides
Part 11 - Angular attribute binding | Text | Slides

In this video we will discuss CSS Class binding in Angular with examples.

For the demos in this video, we will use same example we have been working with so far in this video series. In styles.css file include the following 3 CSS classes. If you recollect styles.css is already referenced in our host page - index.html.



.boldClass{
    font-weight:bold;
}

.italicsClass{
    font-style:italic;
}

.colorClass{
    color:red;
}



In app.component.ts, include a button element as shown below. Notice we have set the class attribute of the button element to 'colorClass'

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button class='colorClass'>My Button</button>
              `
})
export class AppComponent {
}
At this point, run the application and notice that the 'colorClass' is added to the button element as expected.

Replace all the existing css classes with one or more classes

Modify the code in app.component.ts as shown below.
  1. We have introduced a property 'classesToApply' in AppComponent class
  2. We have also specified class binding for the button element. The word 'class' is in a pair of square brackets and it is binded to the property 'classesToApply'
  3. This will replace the existing css classes of the button with classes specified in the class binding
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button class='colorClass' [class]='classesToApply'>My Button</button>
              `
})
export class AppComponent {
    classesToApply: string = 'italicsClass boldClass';
}

Run the application and notice 'colorClass' is removed and these classes (italicsClass & boldClass) are added.

Adding or removing a single class : To add or remove a single class, include the prefix 'class' in a pair of square brackets, followed by a DOT and then the name of the class that you want to add or remove. The following example adds boldClass to the button element. Notice it does not remove the existing colorClass already added using the class attribute. If you change applyBoldClass property to false or remove the property altogether from the AppComponent class, css class boldClass is not added to the button element.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button class='colorClass' [class.boldClass]='applyBoldClass'>My Button</button>
              `
})
export class AppComponent {
    applyBoldClass: boolean = true;
}

With class binding we can also use ! symbol. Notice in the example below applyBoldClass is set to false. Since we have used ! in the class binding the class is added as expected.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button class='colorClass' [class.boldClass]='!applyBoldClass'>My Button</button>
              `
})
export class AppComponent {
    applyBoldClass: boolean = false;
}

You can also removed an existing class that is already applied. Consider the following example. Notice we have 3 classes (colorClass, boldClass & italicsClass) added to the button element using the class attribute. The class binding removes the boldClass.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button class='colorClass boldClass italicsClass'
                        [class.boldClass]='applyBoldClass'>My Button</button>
              `
})
export class AppComponent {
    applyBoldClass: boolean = false;
}

To add or remove multiple classes use ngClass directive as shown in the example below.
  1. Notice the colorClass is added using the class attribute
  2. ngClass is binded to addClasses() method of the AppComponent class
  3. addClasses() method returns an object with 2 key/value pairs. The key is a CSS class name. The value can be true or false. True to add the class and false to remove the class.
  4. Since both the keys (boldClass & italicsClass) are set to true, both classes will be added to the button element
  5. let is a new type of variable declaration in JavaScript.
  6. let is similar to var in some respects but allows us to avoid some of the common gotchas that we run into when using var. 
  7. The differences between let and var are beyond the scope of this video. For our example, var also works fine.
  8. As TypeScript is a superset of JavaScript, it supports let
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button class='colorClass' [ngClass]='addClasses()'>My Button</button>
             `
})
export class AppComponent {
    applyBoldClass: boolean = true;
    applyItalicsClass: boolean = true;

    addClasses() {
        let classes = {
            boldClass: this.applyBoldClass,
            italicsClass: this.applyItalicsClass
        };

        return classes;
    }
}

We have included our css classes in a external stylesheet - styles.css. Please note we can also include these classes in the styles property instead of a separate stylesheet as shown below.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button class='colorClass' [ngClass]='addClasses()'>My Button</button>
             `,
    styles: [`
            .boldClass{
                font-weight:bold;
            }

            .italicsClass{
                font-style:italic;
            }

            .colorClass{
                color:red;
            }
             `]
})
export class AppComponent {
    applyBoldClass: boolean = true;
    applyItalicsClass: boolean = true;

    addClasses() {
        let classes = {
            boldClass: this.applyBoldClass,
            italicsClass: this.applyItalicsClass
        };

        return classes;
    }
}

Video Link


Style binding in angular 2

Suggested Videos
Part 10 - html attribute vs dom property | Text | Slides
Part 11 - Angular attribute binding | Text | Slides
Part 12 - Class binding in angular 2 | Text | Slides

In this video we will discuss Style binding in Angular with examples.

Setting inline styles with style binding is very similar to setting CSS classes with class binding. Please watch Class binding video from Angular 2 tutorial before proceeding with this video.



Notice in the example below, we have set the font color of the button using the style attribute.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button style="color:red">My Button</button>
              `
})
export class AppComponent {
}



The following example sets a single style (font-weight). If the property 'isBold' is true, then font-weight style is set to bold else normal.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button style='color:red'
                        [style.font-weight]="isBold ? 'bold' : 'normal'">My Button
                </button>
              `
})
export class AppComponent {
    isBold: boolean = true;
}

style property name can be written in either dash-case or camelCase. For example, font-weight style can also be written using camel case - fontWeight.

Some styles like font-size have a unit extension. To set font-size in pixels use the following syntax. This example sets font-size to 30 pixels.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                <button style='color:red'
                        [style.font-size.px]="fontSize">My Button
                </button>
              `
})
export class AppComponent {
    fontSize: number = 30;
}

To set multiple inline styles use NgStyle directive as shown below
  • Notice the color style is added using the style attribute
  • ngStyle is binded to addStyles() method of the AppComponent class
  • addStyles() method returns an object with 2 key/value pairs. The key is a style name, and the value is a value for the respective style property or an expression that returns the style value.
  • let is a new type of variable declaration in JavaScript.
  • let is similar to var in some respects but allows us to avoid some of the common gotchas that we run into when using var. 
  • The differences between let and var are beyond the scope of this video. For our example, var also works fine.
  • As TypeScript is a superset of JavaScript, it supports let
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: ` <button style='color:red' [ngStyle]="addStyles()">My Button</button>
                    `
})
export class AppComponent {
    isBold: boolean = true;
    fontSize: number = 30;
    isItalic: boolean = true;

    addStyles() {
        let styles = {
            'font-weight': this.isBold ? 'bold' : 'normal',
            'font-style': this.isItalic ? 'italic' : 'normal',
            'font-size.px': this.fontSize
        };

        return styles;
    }
}

Video Link


Angular2 event binding

Suggested Videos
Part 11 - Angular attribute binding | Text | Slides
Part 12 - Class binding in angular 2 | Text | Slides
Part 13 - Style binding in angular 2 | Text | Slides

In this video we will discuss Event Binding in Angular with examples.



The following bindings that we have discussed so far in this video series flow data in one direction i.e from a component class property to an HTML element property.
1. Interpolation
2. Property Binding
3. Attribute Binding
4. Class Binding
5. Style Binding



How about flowing data in the opposite direction i.e from an HTML element to a component. When a user performs any action like clicking on a button, hovering over an element, selecting from a dropdownlist, typing in a textbox etc, then the corresponding event for that action is raised. We need to know when user performs these actions. We can use angular event binding to get notified when these events occur.

For example the following is the syntax for binding to the click event of a button. Within parentheses on the left of the equal sign we have the target event, (click) in this case and on the right we have the template statement. In this case the onClick() method of the component class is called when the click event occurs.
<button (click)="onClick()">Click me</button>

With event binding we can also use the on- prefix alternative as shown below. This is known as the canonical form
<button on-click="onClick()">Click me</button>

Event Binding Example : 

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<button (click)='onClick()' >Click me</button>`
})
export class AppComponent {
    onClick(): void {
        console.log('Button Clicked');
    }
}

Every time we click the button, 'Button Clicked' message is logged to the console. You can see this message under the Console tab, in the browser developer tools.
angular bind event to element

Another Example : Initially when the page loads we want to display only the First Name and Last of Employee. We also want to display "Show Details" button.

angular 2 click event example

When we click "Show Details" button, we want to display "Gender" and "Age" as well. The text on the button should be changed to "Hide Details". When we click "Hide Details" button, "Gender" and "Age" should be hidden and the button text should be changed to "Show Details".

angular 2 click event binding

To achieve this we will make use of event binding in Angular. We will also make use of one of the structural directives "ngIf" in angular.

Code in employee.component.ts : Notice we have introduced "showDetails" boolean property. The default value is false, so when the page first loads, we will have "Gender" and "Age" hidden. We also have a method, toggleDetails(), which toggles the value of showDetails. 

import { Component } from '@angular/core';

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html',
    styleUrls: ['app/employee/employee.component.css']
})
export class EmployeeComponent {
    columnSpan: number = 2;
    firstName: string = 'Tom';
    lastName: string = 'Hopkins';
    gender: string = 'Male';
    age: number = 20;
    showDetails: boolean = false;

    toggleDetails(): void {
        this.showDetails = !this.showDetails;
    }
}

Code in employee.component.html :
  • Notice the click event of the button is binded to toggleDetails() method
  • To dynamicall change the text on the button, we are using ternary operator - {{showDetails ? 'Hide' : 'Show'}} Details
  • We used ngIf structural directive on "Gender" and "Age" <tr> elements 
  • The * prefix before a directive indicates, it is a structural directive
  • Besides ngIf, there are other structural directives which we will discuss in our upcoming videos
  • The ngIf directive conditionally adds or removes content from the DOM based on whether or not an expression is true or false
  • If "showDetails" is true, "Gender" and "Age" <tr> elements are added to the DOM, else removed
<table>
    <thead>
        <tr>
            <th attr.colspan="{{columnSpan}}">
                Employee Details
            </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>First Name</td>
            <td>{{firstName}}</td>
        </tr>
        <tr>
            <td>Last Name</td>
            <td>{{lastName}}</td>
        </tr>
        <tr *ngIf='showDetails'>
            <td>Gender</td>
            <td>{{gender}}</td>
        </tr>
        <tr *ngIf='showDetails'>
            <td>Age</td>
            <td>{{age}}</td>
        </tr>
    </tbody>
</table>
<br />
<button (click)='toggleDetails()'>
    {{showDetails ? 'Hide' : 'Show'}} Details
</button>

Video Link


Two way data binding in angular 2

Suggested Videos
Part 12 - Class binding in angular 2 | Text | Slides
Part 13 - Style binding in angular 2 | Text | Slides
Part 14 - Angular2 event binding | Text | Slides

In this video we will discuss Two way Data Binding in Angular 2.

Consider the following code in app.component.ts

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                Name : <input [value]='name'>
                <br>
                You entered : {{name}}
              `
})
export class AppComponent {
    name: string = 'Tom';
}


  • <input [value]='name'> : Binds component class "name" property to the input element’s value property
  • You entered : {{name}} : Interpolation displays the value we have in "name" property on the web page

Here is the output
Two way data binding in angular 2

At the moment when we change the value in the textbox, that changed value is not reflected in the browser. One way to achieve this is by binding to the input event of the input control as shown below.

Name : <input [value]='name' (input)='name = $event.target.value'>
<br>
You entered : {{name}}

At this point, as we type in the textbox, the changed value is displayed on the page.

angular 2 2 way binding example

So let's understand what is happening here. Conside this code 

Name : <input [value]='name' (input)='name = $event.target.value'>
<br>
You entered : {{name}}
  • [value]='name' : This property binding flows data from the component class to element property 
  • (input)='name = $event.target.value' : This event binding flows data in the opposite direction i.e from the element to component class property "name"
  • $event - Is exposed by angular event binding, and contains the event data. To retrieve the value from the input element use - $event.target.value.
  • name = $event.target.value - This expression updates the value in the name property in the component class
  • You entered : {{name}} - This interpolation expression will then display the value on the web page.
So in short two-way data binding in Angular is a combination of both Property Binding and Event Binding. To save a few keystrokes and simplify two-way data binding angular has provided ngModel directive. So with ngModel directive we can rewrite the following line of code
Name : <input [value]='name' (input)='name = $event.target.value'>

Like this : Name : <input [(ngModel)]='name'>

At this point if you view the page in the browser, you will get the following error
Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'

This is because ngModel directive is, in an Angular system module called FormsModule. For us to be able to use ngModel directive in our root module - AppModule, we will have to import FormsModule first.

Here are the steps to import FormsModule into our AppModule
1. Open app.module.ts file
2. Include the following import statement in it
    import { FormsModule } from '@angular/forms';
3. Also, include FormsModule in the 'imports' array of @NgModule
    imports: [BrowserModule, FormsModule]

With these changes, reload the web page and it will work as expected.

So here is the syntax for using two-way data binding in Angular
<input [(ngModel)]='name'>
  • The square brackets on the outside are for property binding 
  • The parentheses on the inside are for event binding
  • To easily remember this syntax, compare it to a banana in a box [()]
Video Link


Angular ngFor directive

Suggested Videos
Part 13 - Style binding in angular 2 | Text | Slides
Part 14 - Angular2 event binding | Text | Slides
Part 15 - Two way data binding in angular 2 | Text | Slides

In Part 14 of Angular 2 tutorial we discussed ngIf structural directive which conditionally adds or removes DOM elements. In this video we will discuss another structural directive - ngFor in Angular. 



Let us understand ngFor structural directive with an example. Consider the following array of Employee objects.

employees: any[] = [
    {
        code: 'emp101', name: 'Tom', gender: 'Male',
        annualSalary: 5500, dateOfBirth: '25/6/1988'
    },
    {
        code: 'emp102', name: 'Alex', gender: 'Male',
        annualSalary: 5700.95, dateOfBirth: '9/6/1982'
    },
    {
        code: 'emp103', name: 'Mike', gender: 'Male',
        annualSalary: 5900, dateOfBirth: '12/8/1979'
    },
    {
        code: 'emp104', name: 'Mary', gender: 'Female',
        annualSalary: 6500.826, dateOfBirth: '14/10/1980'
    },
];



We want to display these employees in a table on a web page as shown below.
Angular ngFor directive

We will use the same project that we have been working with so far in this video series. 

Step 1 : Add a new TypeScript file to the "employee" folder. Name it employeeList.component.ts. Copy and paste the following code in it.

import { Component } from '@angular/core';

@Component({
    selector: 'list-employee',
    templateUrl: 'app/employee/employeeList.component.html',
    styleUrls: ['app/employee/employeeList.component.css']
})
export class EmployeeListComponent {
    employees: any[] = [
        {
            code: 'emp101', name: 'Tom', gender: 'Male',
            annualSalary: 5500, dateOfBirth: '25/6/1988'
        },
        {
            code: 'emp102', name: 'Alex', gender: 'Male',
            annualSalary: 5700.95, dateOfBirth: '9/6/1982'
        },
        {
            code: 'emp103', name: 'Mike', gender: 'Male',
            annualSalary: 5900, dateOfBirth: '12/8/1979'
        },
        {
            code: 'emp104', name: 'Mary', gender: 'Female',
            annualSalary: 6500.826, dateOfBirth: '14/10/1980'
        },
    ];
}

Step 2 : Add a new HTML page to the "employee" folder. Name it employeeList.component.html. Copy and paste the following code in it.

Please note :
  • ngFor is usually used to display an array of items
  • Since ngFor is a structural directive it is prefixed with *
  • *ngFor='let employee of employees' - In this example 'employee' is called template input variable, which can be accessed by the <tr> element and any of it's child elements.
  • ngIf structural directive displays the row "No employees to display" when employees property does not exist or when there are ZERO employees in the array.
<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor='let employee of employees'>
            <td>{{employee.code}}</td>
            <td>{{employee.name}}</td>
            <td>{{employee.gender}}</td>
            <td>{{employee.annualSalary}}</td>
            <td>{{employee.dateOfBirth}}</td>
        </tr>
        <tr *ngIf="!employees || employees.length==0">
            <td colspan="5">
                No employees to display
            </td>
        </tr>
    </tbody>
</table>

Step 3 :  Add a new StyleSheet to the "employee" folder. Name it employeeList.component.css. Copy and paste the following code in it.

table {
    color: #369;
    font-family: Arial, Helvetica, sans-serif;
    font-size: large;
    border-collapse: collapse;
}

td {
    border: 1px solid #369;
    padding:5px;
}

th{
    border: 1px solid #369;
    padding:5px;
}

Step 4 : In the root module, i.e app.module.ts, import employeeList component and add it to the declarations array as shown below.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { EmployeeComponent } from './employee/employee.component';
import { EmployeeListComponent } from './employee/employeeList.component';

@NgModule({
    imports: [BrowserModule],
    declarations: [AppComponent, EmployeeComponent, EmployeeListComponent],
    bootstrap: [AppComponent]
})

export class AppModule { }

Step 5 : In the root component, i.e app.component.ts use employeeList component as a directive as shown below.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<list-employee></list-employee>`
})

export class AppComponent { }
At this point, run the application and notice the employees are displayed in the table as expected.

Video Link


Angular ngFor trackBy

Suggested Videos
Part 14 - Angular2 event binding | Text | Slides
Part 15 - Two way data binding in angular 2 | Text | Slides
Part 16 - Angular ngFor directive | Text | Slides

In this video we will discuss 
1. Using trackyBy with ngFor directive
2. How to get the index of an item in a collection
3. Identifying the first and the last elements in a collection
4. Identifying even and odd elements in a collection



Using trackyBy with ngFor directive : 
  • ngFor directive may perform poorly with large lists
  • A small change to the list like, adding a new item or removing an existing item may trigger a cascade of DOM manipulations


For example, consider this code in employeeList.component.ts

The constructor() initialises the employees property with 4 employee objects
getEmployees() method returns another list of 5 employee objects (The 4 existing employees plus a new employee object)

import { Component } from '@angular/core';

@Component({
    selector: 'list-employee',
    templateUrl: 'app/employee/employeeList.component.html',
    styleUrls: ['app/employee/employeeList.component.css']
})
export class EmployeeListComponent {
    employees: any[];

    constructor() {
        this.employees = [
            {
                code: 'emp101', name: 'Tom', gender: 'Male',
                annualSalary: 5500, dateOfBirth: '25/6/1988'
            },
            {
                code: 'emp102', name: 'Alex', gender: 'Male',
                annualSalary: 5700.95, dateOfBirth: '9/6/1982'
            },
            {
                code: 'emp103', name: 'Mike', gender: 'Male',
                annualSalary: 5900, dateOfBirth: '12/8/1979'
            },
            {
                code: 'emp104', name: 'Mary', gender: 'Female',
                annualSalary: 6500.826, dateOfBirth: '14/10/1980'
            },
        ];
    }

    getEmployees(): void {
        this.employees = [
            {
                code: 'emp101', name: 'Tom', gender: 'Male',
                annualSalary: 5500, dateOfBirth: '25/6/1988'
            },
            {
                code: 'emp102', name: 'Alex', gender: 'Male',
                annualSalary: 5700.95, dateOfBirth: '9/6/1982'
            },
            {
                code: 'emp103', name: 'Mike', gender: 'Male',
                annualSalary: 5900, dateOfBirth: '12/8/1979'
            },
            {
                code: 'emp104', name: 'Mary', gender: 'Female',
                annualSalary: 6500.826, dateOfBirth: '14/10/1980'
            },
            {
                code: 'emp105', name: 'Nancy', gender: 'Female',
                annualSalary: 6700.826, dateOfBirth: '15/12/1982'
            },
        ];
    }
}

Now look at this code in employeeList.component.html
<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor='let employee of employees'>
            <td>{{employee.code}}</td>
            <td>{{employee.name}}</td>
            <td>{{employee.gender}}</td>
            <td>{{employee.annualSalary}}</td>
            <td>{{employee.dateOfBirth}}</td>
        </tr>
        <tr *ngIf="!employees || employees.length==0">
            <td colspan="5">
                No employees to display
            </td>
        </tr>
    </tbody>
</table>
<br />
<button (click)='getEmployees()'>Refresh Employees</button>

At the moment we are not using trackBy with ngFor directive
  1. When the page initially loads we see the 4 employees
  2. When we click "Refresh Employees" button we see the fifth employee as well
  3. It looks like it just added the additional row for the fifth employee. That's not true, it effectively teared down all the <tr> and <td> elements of all the employees and recreated them.
  4. To confirm this launch browser developer tools by pressing F12.
  5. Click on the "Elements" tab and expand the <table> and then <tbody> elements
  6. At this point click the "Refresh Employees" button and you will notice all the <tr> elements are briefly highlighted indicating they are teared down and recreated.
Angular ngFor trackBy

This happens because Angular by default keeps track of objects using the object references. When we click "Refresh Employees" button we get different object references and as a result Angular has no choice but to tear down all the old DOM elements and insert the new DOM elements.

Angular can avoid this churn with trackBy. The trackBy function takes the index and the current item as arguments and returns the unique identifier by which that item should be tracked. In our case we are tracking by Employee code. Add this method to employeeList.component.ts

trackByEmpCode(index: number, employee: any): string {
    return employee.code;
}

Make the following change in employeeList.component.html : Notice along with ngFor we also specified trackBy

<tr *ngFor='let employee of employees; trackBy:trackByEmpCode'>

At this point, run the application and launch developer tools. When you click "Refresh Employees" first time, only the the row of the fifth employee is highlighted indicating only that<tr> element is added. On subsequent clicks, nothing is highlighted meaning none of the <tr> elements are teared down or added as the employees collection has not changed. Even now we get different object references when we click "Refresh Employees" button, but as Angular is now tracking employee objects using the employee code instead of object references, the respective DOM elements are not affected.

How to get the index of an item in a collection : Notice in the example below, we are using the index property of the ngFor directive to store the index in a template input variable "i". The variable is then used in the <td> element where we want to display the index. We used the let keyword to create the template input variable "i". 

The index of an element is extremely useful when creating the HTML elements dynamically. We will discuss creating HTML elements dynamically in our upcoming videos.

<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
            <th>Index</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor='let employee of employees; let i=index'>
            <td>{{employee.code}}</td>
            <td>{{employee.name}}</td>
            <td>{{employee.gender}}</td>
            <td>{{employee.annualSalary}}</td>
            <td>{{employee.dateOfBirth}}</td>
            <td>{{i}}</td>
        </tr>
        <tr *ngIf="!employees || employees.length==0">
            <td colspan="5">
                No employees to display
            </td>
        </tr>
    </tbody>
</table>

Notice the index of the element is displayed int the last <td> element
angular ngfor index example

Identifying the first and the last element in a collection : Use the first and last properties of the ngFor directive to find if an element is the first or last element respectively.

Modify the code in employeeList.component.html as shown below.

<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
            <th>Is First</th>
            <th>Is Last</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor='let employee of employees; let isFirst = first; let isLast = last'>
            <td>{{employee.code}}</td>
            <td>{{employee.name}}</td>
            <td>{{employee.gender}}</td>
            <td>{{employee.annualSalary}}</td>
            <td>{{employee.dateOfBirth}}</td>
            <td>{{isFirst}}</td>
            <td>{{isLast}}</td>
        </tr>
        <tr *ngIf="!employees || employees.length==0">
            <td colspan="5">
                No employees to display
            </td>
        </tr>
    </tbody>
</table>
<br />
<button (click)='getEmployees()'>Refresh Employees</button>

The output is shown below
angular ngfor first

Identifying even and odd element in a collection : This is similar to identifying first and last element in a collection. Instead of using first and last properties, use even and odd properties.

Here is the code in employeeList.component.html

<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
            <th>Is Even</th>
            <th>Is Odd</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor='let employee of employees; let isEven = even; let isOdd = odd'>
            <td>{{employee.code}}</td>
            <td>{{employee.name}}</td>
            <td>{{employee.gender}}</td>
            <td>{{employee.annualSalary}}</td>
            <td>{{employee.dateOfBirth}}</td>
            <td>{{isEven}}</td>
            <td>{{isOdd}}</td>
        </tr>
        <tr *ngIf="!employees || employees.length==0">
            <td colspan="5">
                No employees to display
            </td>
        </tr>
    </tbody>
</table>
<br />
<button (click)='getEmployees()'>Refresh Employees</button>

The output is shown below
angular ngfor even odd

Video Link


Angular pipes

Suggested Videos
Part 15 - Two way data binding in angular 2 | Text | Slides
Part 16 - Angular ngFor directive | Text | Slides
Part 17 - Angular ngFor trackBy | Text | Slides

In this video we will discuss Pipes in Angular with examples.



Pipes in Angular
  • Transform data before display
  • Built in pipes include lowercase, uppercase, decimal, date, percent, currency etc
Please note : If you get the following error, chances are that your date is not in mm/dd/yyyy format. To fix this error please change the date format to mm/dd/yyyy or create a custom pipe
InvalidPipeArgument: '14/10/1980' for pipe 'DatePipe'

Angular Pipe Examples:

uppercase pipe in this example converts employee code to uppercase
<td>{{employee.code | uppercase}}</td>

Output : 
angular 2 uppercase pipe

In this example, we have chained date and uppercase pipes.
<td>{{employee.dateOfBirth | date:'fullDate' | uppercase }}</td>

Output : 
angular 2 pipe chain

In this example we are passing a single parameter to date pipe. With the parameter we specified we want the date format to be dd/mm/yyyy
<td>{{employee.dateOfBirth | date:'dd/MM/y'}}</td>

Output : 
angular2 date pipe example

For the list of date pipe parameter values please check the following article
https://angular.io/api/common/DatePipe

In this example we are passing 3 parameters to the currency pipe
<td>{{employee.annualSalary | currency:'USD':true:'1.3-3'}}</td>
  1. The first parameter is the currencyCode
  2. The second parameter is boolean - True to display currency symbol, false to display currency code
  3. The third parameter ('1.3-3') specifies the number of integer and fractional digits
Output : 
angular 2 currency pipe example

Video Link


Angular custom pipe

Suggested Videos
Part 16 - Angular ngFor directive | Text | Slides
Part 17 - Angular ngFor trackBy | Text | Slides
Part 18 - Angular Pipes | Text | Slides

In this video we will discuss creating a Custom Pipe in Angular. Let us understand this with an example.



Here is what we want to do. Depending on the gender of the employee, we want to display Mr. or Miss. prefixed to the employee name as shown below.
how to create custom pipe in angular 2



Step 1 : To achieve this let's create a custom pipe called employeeTitlePipe. Right click on the "employee" folder and add a new TypeScript file. Name it "employeeTitle.pipe.ts". Copy and paste the following code.

Code Explanation : 
  • Import Pipe decorator and PipeTransform interface from Angular core
  • Notice "EmployeeTitlePipe" class is decorated with Pipe decorator to make it an Angular pipe
  • name property of the pipe decorator is set to employeeTitle. This name can then be used on any HTML page where you want this pipe functionality.
  • EmployeeTitlePipe class implements the PipeTransform interface. This interface has one method transform() which needs to be implemented.
  • Notice the transform method has 2 parameters. value parameter will receive the name of the employee and gender parameter receives the gender of the employee. The method returns a string i.e Mr. or Miss. prefixed to the name of the employee depending on their gender.
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'employeeTitle'
})
export class EmployeeTitlePipe implements PipeTransform {
    transform(value: string, gender: string): string {
        if (gender.toLowerCase() == "male")
            return "Mr." + value;
        else
            return "Miss." + value;
    }
}

Step 2 : Register "EmployeeTitlePipe" in the angular module where we need it. In our case we need it in the root module. So in app.module.ts file, import the EmployeeTitlePipe and include it in the "declarations" array of NgModule decorator

import { EmployeeTitlePipe } from './employee/employeeTitle.pipe'

@NgModule({
    imports: [BrowserModule],
    declarations: [AppComponent, EmployeeComponent,
                   EmployeeListComponent, EmployeeTitlePipe],
    bootstrap: [AppComponent]
})

export class AppModule { }

Step 3 : In "employeeList.component.html" use the "EmployeeTitlePipe" as shown below. Notice we are passing employee gender as an argument for the gender parameter of our custom pipe. Employee name gets passed automatically.

<tr *ngFor='let employee of employees;'>
    <td>{{employee.code}}</td>
    <td>{{employee.name | employeeTitle:employee.gender}}</td>
    <td>{{employee.gender}}</td>
    <td>{{employee.annualSalary}}</td>
    <td>{{employee.dateOfBirth}}</td>
</tr>

Video Link


Angular 2 container and nested components

Suggested Videos
Part 17 - Angular ngFor trackBy | Text | Slides
Part 18 - Angular Pipes | Text | Slides
Part 19 - Angular custom pipe | Text | Slides

In this video and in the next few videos we will discuss
  • What is a nested component 
  • What is a container component 
  • Passing data from the nested component to container component 
  • Passing data from the container component to nested component
  • Along the way we will discuss component input and output properties
  • Creating custom events using EventEmitter class
  • What is ng-container directive and it's use

We will use the following example to understand all of the above concepts. Notice we have a table that displays a list of employees. 
angular 2 component input output


Above the table we have 3 radio buttons. Next to each radio button we also have the count of employees. 
passing data between components angular 2

All(5) radio button has the total count of employees. Male(3) radio button has the total count of male employees and the Female(2) radio button has the total count of female employees. 

At the moment All(5) radio button is selected, so all the employees are displayed in the table. If I select Male(3) radio button, then only the 3 male employees should be displayed in the table. Along the same lines,if Female(2) radio button is selected only the female employees should be displayed.

As we develop this example, we will understand all the following concepts.
  • What is a container and nested component 
  • Passing data from the nested component to container component and vice-versa
  • Component input and output properties
  • Creating custom events using EventEmitter class
  • What is ng-container directive and it's use
What is a container and nested component : In the example below, we have 2 components

One of the component displays the list of employees. We have already built this component in our previous videos in this series. We named this component EmployeeListComponent.

The other component displays the radio buttons and the count of employees. We have not created this component yet. We will create it in this video. We will call this component EmployeeCountComponent.

We will nest EmployeeCountComponent in EmployeeListComponent. So EmployeeCountComponent becomes the nested component or child component and EmployeeListComponent becomes the container component or parent component.

Angular 2 container and nested components

We have already implemented the required code for EmployeeListComponent in our previous videos as shown below.

employeeList.component.ts

import { Component } from '@angular/core';

@Component({
    selector: 'list-employee',
    templateUrl: 'app/employee/employeeList.component.html',
    styleUrls: ['app/employee/employeeList.component.css']
})
export class EmployeeListComponent {
    employees: any[];

    constructor() {
        this.employees = [
            {
                code: 'emp101', name: 'Tom', gender: 'Male',
                annualSalary: 5500, dateOfBirth: '6/25/1988'
            },
            {
                code: 'emp102', name: 'Alex', gender: 'Male',
                annualSalary: 5700.95, dateOfBirth: '9/6/1982'
            },
            {
                code: 'emp103', name: 'Mike', gender: 'Male',
                annualSalary: 5900, dateOfBirth: '12/8/1979'
            },
            {
                code: 'emp104', name: 'Mary', gender: 'Female',
                annualSalary: 6500.826, dateOfBirth: '10/14/1980'
            },
            {
                code: 'emp105', name: 'Nancy', gender: 'Female',
                annualSalary: 6700.826, dateOfBirth: '12/15/1982'
            },
        ];
    }
}

employeeList.component.html

<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let employee of employees;">
            <td>{{employee.code | uppercase}}</td>
            <td>{{employee.name | employeeTitle:employee.gender }}</td>
            <td>{{employee.gender}}</td>
            <td>{{employee.annualSalary | currency:'USD':true:'1.3-3'}}</td>
            <td>{{employee.dateOfBirth | date:'dd/MM/y'}}</td>
        </tr>
        <tr *ngIf="!employees || employees.length==0">
            <td colspan="5">
                No employees to display
            </td>
        </tr>
    </tbody>
</table>

employeeList.component.css

table {
    color: #369;
    font-family: Arial, Helvetica, sans-serif;
    font-size: large;
    border-collapse: collapse;
}

td {
    border: 1px solid #369;
    padding:5px;
}

th{
    border: 1px solid #369;
    padding:5px;
}

Now let's create the EmployeeCountComponent. Add a new TypeScript file to the employee folder. Name it employeeCount.component.ts. Copy and paste the following code.

employeeCount.component.ts
  • We have set select='employee-count'. We can use this selector as a directive where we want to use this component. We are going to nest this component inside EmployeeListComponent using employee-count selector as a directive.
  • We have 3 properties (all, male and Female). At the moment we have hard coded the values. In our next video we will discuss how to pass the values for these properties from the container component i.e from the EmployeeListComponent.
import { Component } from '@angular/core';

@Component({
    selector: 'employee-count',
    templateUrl: 'app/employee/employeeCount.component.html',
    styleUrls: ['app/employee/employeeCount.component.css']
})
export class EmployeeCountComponent {
    all: number = 10;
    male: number = 5;
    female: number = 5;
}

Add a new StyleSheet to the employee folder. Name it employeeCount.component.css. Copy and paste the following style class.

employeeCount.component.css

.radioClass {
    color: #369;
    font-family: Arial, Helvetica, sans-serif;
    font-size: large;
}

Now let's add the view template for EmployeeCountComponent. Add a new HTML page to the employee folder. Name it employeeCount.component.html. Copy and paste the following html.

employeeCount.component.html

Notice we have 3 radio buttons and bound them to the 3 properties (all, male, female) we have in the component class. We are using interpolation for data-binding.

<span class="radioClass">Show : </span>

<input type="radio" name="options" />
<span class="radioClass">{{"All(" + all + ")"}}</span>

<input name="options" type="radio">
<span class="radioClass">{{"Male(" + male + ")"}}</span>

<input name="options" type="radio">
<span class="radioClass">{{"Female(" + female + ")"}}</span>

Nest EmployeeCountComponent in EmployeeListComponent component. To do this, use EmployeeCountComponent selector (employee-count) as a directive <employee-count></employee-count> on EmployeeListComponent component as shown below.

<employee-count></employee-count>
<br /><br />
<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let employee of employees;">
            <td>{{employee.code | uppercase}}</td>
            <td>{{employee.name | employeeTitle:employee.gender }}</td>
            <td>{{employee.gender}}</td>
            <td>{{employee.annualSalary | currency:'USD':true:'1.3-3'}}</td>
            <td>{{employee.dateOfBirth | date:'dd/MM/y'}}</td>
        </tr>
        <tr *ngIf="!employees || employees.length==0">
            <td colspan="5">
                No employees to display
            </td>
        </tr>
    </tbody>
</table>

Finally, declare EmployeeCountComponent in module.ts file. Please make sure you import the component first and then add it to the declarations array of @NgModule decorator.

import { EmployeeCountComponent } from './employee/employeeCount.component';

@NgModule({
    imports: [BrowserModule, FormsModule],
    declarations: [AppComponent, EmployeeComponent,
        EmployeeListComponent, EmployeeTitlePipe, EmployeeCountComponent],
    bootstrap: [AppComponent]
})

export class AppModule { }

At this point, run the project and you should see employee count radio buttons and the employee list.

At the moment the employee counts are hard coded with in the EmployeeCountComponent. In our next video we will discuss how to pass the count values from the container component i.e from the EmployeeListComponent to the nested component i.e EmployeeCountComponent.

Video Link


Angular component input properties

Suggested Videos
Part 18 - Angular Pipes | Text | Slides
Part 19 - Angular custom pipe | Text | Slides
Part 20 - Angular 2 container and nested components | Text | Slides

In this video we will discuss how to pass data from the container component to the nested component using input properties

This is continuation to Part 20, so please watch Part 20 from Angular 2 tutorial before proceeding. We will be working with the same example, we started in Part 20.



At the moment the count of employees displayed against each radio button are hard-coded with in the EmployeeCountComponent.
angular component input parameter



Here is the code in employeeCount.component.ts file : Notice the values for the 3 properties (all, male, female) are hard-coded. We want the values for these 3 properties to be passed from the container component i.e EmployeeListComponent.

export class EmployeeCountComponent {
    all: number = 10;
    male: number = 5;
    female: number = 5;
}

Convert a component property to an input property using @Input decorator : To be able to pass the values for these 3 properties from the container component to the nested component we need to decorate the properties with @Input() decorator. Decorating a property with @Input() decorator makes the property an input property. Notice I have also removed the default hard-coded values, as we will be passing the values from the parent component i.e EmployeeListComponent. To be able to use the @Input() decorator we will have to first import it from @angular/core.

import { Component, Input } from '@angular/core';

@Component({
    selector: 'employee-count',
    templateUrl: 'app/employee/employeeCount.component.html',
    styleUrls: ['app/employee/employeeCount.component.css']
})
export class EmployeeCountComponent {
    @Input()
    all: number;

    @Input()
    male: number;

    @Input()
    female: number;
}

Passing data from the parent component to the child component : There are 2 modifications that we need to do in EmployeeListComponent to be able to pass values from the parent component i.e EmployeeListComponent to the child component i.e EmployeeCountComponent. The first change is in EmployeeListComponent TypeScript file as shown below. Notice I have introduced 3 methods that return male employees count, female employees count and total employees count.

import { Component } from '@angular/core';

@Component({
    selector: 'list-employee',
    templateUrl: 'app/employee/employeeList.component.html',
    styleUrls: ['app/employee/employeeList.component.css']
})
export class EmployeeListComponent {
    employees: any[];

    constructor() {
        this.employees = [
            {
                code: 'emp101', name: 'Tom', gender: 'Male',
                annualSalary: 5500, dateOfBirth: '6/25/1988'
            },
            {
                code: 'emp102', name: 'Alex', gender: 'Male',
                annualSalary: 5700.95, dateOfBirth: '9/6/1982'
            },
            {
                code: 'emp103', name: 'Mike', gender: 'Male',
                annualSalary: 5900, dateOfBirth: '12/8/1979'
            },
            {
                code: 'emp104', name: 'Mary', gender: 'Female',
                annualSalary: 6500.826, dateOfBirth: '10/14/1980'
            },
            {
                code: 'emp105', name: 'Nancy', gender: 'Female',
                annualSalary: 6700.826, dateOfBirth: '12/15/1982'
            },
        ];
    }

    getTotalEmployeesCount(): number {
        return this.employees.length;
    }

    getMaleEmployeesCount(): number {
        return this.employees.filter(e => e.gender === 'Male').length;
    }

    getFemaleEmployeesCount(): number {
        return this.employees.filter(e => e.gender === 'Female').length;
    }
}

Please note : In the filter method we are using tripple equals (===) instead of double equals (==). The table below explains single, double and tripple equals in TypeScript.

Operator Use to
= Assign a value
== Compare two values
=== Compare two values and their types

The second change is in the view template of EmployeeListComponent i.e employeeList.component.html file. Notice with in <employee-count> directive we are using property binding to bind the properties (all, male, female) of the nested component (EmployeeCountComponent) with the 3 methods in the container component (EmployeeListComponent).

<employee-count [all]="getTotalEmployeesCount()"
                [male]="getMaleEmployeesCount()"
                [female]="getFemaleEmployeesCount()">
</employee-count>
<br /><br />
<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let employee of employees;">
            <td>{{employee.code | uppercase}}</td>
            <td>{{employee.name | employeeTitle:employee.gender }}</td>
            <td>{{employee.gender}}</td>
            <td>{{employee.annualSalary | currency:'USD':true:'1.3-3'}}</td>
            <td>{{employee.dateOfBirth | date:'dd/MM/y'}}</td>
        </tr>
        <tr *ngIf="!employees || employees.length==0">
            <td colspan="5">
                No employees to display
            </td>
        </tr>
    </tbody>
</table>

At this point, save all the changes and run the application and we see the correct count of employee next to each radio button.

angular component communication

Now, let's add the following new employee object to the to the employees array in EmployeeListComponent.

{
    code: 'emp106', name: 'Steve', gender: 'Male',
    annualSalary: 7700.481, dateOfBirth: '11/18/1979'
}

Save changes and reload the web page and notice that All count and Male count is increased by 1 as expected.
parent child component communication angular2

At the moment when we click the radio buttons nothing happens. In our next video we will discuss how to pass data from the child component to the parent component i.e when a radio button checked event is raised in the child component, we want to know about it in the parent component so we can react and decide which employees to show in the table depending on the selection of the radio button.

Video Link


Angular component output properties

Suggested Videos
Part 19 - Angular custom pipe | Text | Slides
Part 20 - Angular 2 container and nested components | Text | Slides
Part 21 - Angular component input properties | Text | Slides

In this video we will discuss 
  • How to pass user actions or user entered values or selections from the child component to the parent component using output properties.
  • Along the way we will discuss creating custom events using angular EventEmitter class
  • Finally what is ng-container directive and it's use


This is continuation to Part 21, so please watch Part 21 from Angular 2 tutorial before proceeding. We will be working with the same example, we started in Part 20.

angular2 eventemitter between components



At the moment when we click the radio buttons, nothing happens. Here is what we want to do.

User Action What should happen
All(6) radio button is clicked Display all the employees in the table
Male(4) radio button is clicked Display the 4 Male employees in the table
Female(2) radio button is clicked Display the 2 Female employees in the table

To achieve this we are going to make use of component output properties. First let's look at the changes required in the nested component i.e EmployeeCountComponent.

The changes required in employeeCount.component.ts are commented and self-explanatory

// Import Output and EventEmitter
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
    selector: 'employee-count',
    templateUrl: 'app/employee/employeeCount.component.html',
    styleUrls: ['app/employee/employeeCount.component.css']
})
export class EmployeeCountComponent {
    @Input()
    all: number;

    @Input()
    male: number;

    @Input()
    female: number;

    // Holds the selected value of the radio button
    selectedRadioButtonValue: string = 'All';

    // The Output decorator makes the property an Output property
    // EventEmitter class is used to create the custom event
    // When the radio button selection changes, the selected
    // radio button value which is a string gets passed to the
    // event handler method. Hence, the event payload is string.
    @Output()
    countRadioButtonSelectionChanged: EventEmitter<string> =
                                        new EventEmitter<string>();

    // This method raises the custom event. We will bind this
    // method to the change event of all the 3 radio buttons
    onRadioButtonSelectionChange() {
        this.countRadioButtonSelectionChanged
            .emit(this.selectedRadioButtonValue);
    }
}

The following are the changes required in the view template of EmployeeCountComponent i.e employeeCount.component.html. Notice we have made 3 changes on each radio button
  1. value attribute is set to (All, Male or Female)
  2. Implemented 2 way data-binding using the ngModel directive. Notice ngModel is bound to selectedRadioButtonValue property in the component class. This 2 way data-binding ensures whenever the radio button selection changes, the selectedRadioButtonValue property is updated with the value of the selected radio button.
  3. onRadioButtonSelectionChange() method is binded to "change" event of the radio button. So this means whenever, the selection of the radio button changes, onRadioButtonSelectionChange() method raises the custom event "countRadioButtonSelectionChanged". We defined this custom event using Angular EventEmitter class.
<span class="radioClass">Show : </span>

<input name='options' type='radio' value="All"
       [(ngModel)]="selectedRadioButtonValue"
       (change)="onRadioButtonSelectionChange()">
<span class="radioClass">{{'All(' + all + ')'}}</span>

<input name="options" type="radio" value="Male"
       [(ngModel)]="selectedRadioButtonValue"
       (change)="onRadioButtonSelectionChange()">
<span class="radioClass">{{"Male(" + male + ")"}}</span>

<input name="options" type="radio" value="Female"
       [(ngModel)]="selectedRadioButtonValue"
       (change)="onRadioButtonSelectionChange()">

<span class="radioClass">{{"Female(" + female + ")"}}</span>

Now let's look at the changes required in the parent component i.e EmployeeListComponent

The following are the changes required in the EmployeeListComponent class i.e employeeList.component.ts. The changes are commented and self-explanatory

import { Component } from '@angular/core';

@Component({
    selector: 'list-employee',
    templateUrl: 'app/employee/employeeList.component.html',
    styleUrls: ['app/employee/employeeList.component.css']
})

export class EmployeeListComponent {
    employees: any[];

    // This property keeps track of which radio button is selected
    // We have set the default value to All, so all the employees
    // are displayed in the table by default
    selectedEmployeeCountRadioButton: string = 'All';

    constructor() {
        this.employees = [
            {
                code: 'emp101', name: 'Tom', gender: 'Male',
                annualSalary: 5500, dateOfBirth: '6/25/1988'
            },
            {
                code: 'emp102', name: 'Alex', gender: 'Male',
                annualSalary: 5700.95, dateOfBirth: '9/6/1982'
            },
            {
                code: 'emp103', name: 'Mike', gender: 'Male',
                annualSalary: 5900, dateOfBirth: '12/8/1979'
            },
            {
                code: 'emp104', name: 'Mary', gender: 'Female',
                annualSalary: 6500.826, dateOfBirth: '10/14/1980'
            },
            {
                code: 'emp105', name: 'Nancy', gender: 'Female',
                annualSalary: 6700.826, dateOfBirth: '12/15/1982'
            },
            {
                code: 'emp106', name: 'Steve', gender: 'Male',
                annualSalary: 7700.481, dateOfBirth: '11/18/1979'
            },
        ];
    }

    getTotalEmployeesCount(): number {
        return this.employees.length;
    }

    getMaleEmployeesCount(): number {
        return this.employees.filter(e => e.gender === 'Male').length;
    }

    getFemaleEmployeesCount(): number {
        return this.employees.filter(e => e.gender === 'Female').length;
    }

    // Depending on which radio button is selected, this method updates
    // selectedEmployeeCountRadioButton property declared above
    // This method is called when the child component (EmployeeCountComponent)
    // raises the custom event - countRadioButtonSelectionChanged
    // The event binding is specified in employeeList.component.html
    onEmployeeCountRadioButtonChange(selectedRadioButtonValue: string): void {
        this.selectedEmployeeCountRadioButton = selectedRadioButtonValue;
    }
}

The following are the changes required in the view template of EmployeeListComponent i.e employeeList.component.html. 

1. onEmployeeCountRadioButtonChange($event) method is bound to the custom event - countRadioButtonSelectionChanged. The $event object will have the selected radio button value as that is what is passed as the event payload from the nested component. The event handler method (onEmployeeCountRadioButtonChange()) in the component class updates the property "selectedEmployeeCountRadioButton". This property is then used along with *ngIf structural directive to decide which employee objects to display in the table.

2. On the <tr> element, we are using "ngIf" directive along with selectedEmployeeCountRadioButton property which controls the employee objects to display. Notice, just above the <tr> element, we have introduced <ng-container> element and the "ngFor" directive is placed on this element. If you are wondering why we have done this, Angular does not allow multiple structural directives to be placed on one element as shown below. 

<tr *ngFor="let employee of employees;"
    *ngIf="selectedEmployeeCountRadioButton=='All'
    || selectedEmployeeCountRadioButton==employee.gender">

The above line of code raises the following error
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with *.

employeeList.component.html

<employee-count [all]="getTotalEmployeesCount()"
                [male]="getMaleEmployeesCount()"
                [female]="getFemaleEmployeesCount()"
                (countRadioButtonSelectionChanged)="onEmployeeCountRadioButtonChange($event)">
</employee-count>
<br /><br />
<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
        </tr>
    </thead>
    <tbody>
        <ng-container *ngFor="let employee of employees;">
            <tr *ngIf="selectedEmployeeCountRadioButton=='All' ||
                       selectedEmployeeCountRadioButton==employee.gender">
                <td>{{employee.code | uppercase}}</td>
                <td>{{employee.name | employeeTitle:employee.gender }}</td>
                <td>{{employee.gender}}</td>
                <td>{{employee.annualSalary | currency:'USD':true:'1.3-3'}}</td>
                <td>{{employee.dateOfBirth | date:'dd/MM/y'}}</td>
            </tr>
        </ng-container>
        <tr *ngIf="!employees || employees.length==0">
            <td colspan="5">
                No employees to display
            </td>
        </tr>
    </tbody>
</table>

At this point, run the application and test. Notice, the correct set of employees are displayed based on the selection of the radio button.

Video Link


Interfaces in Angular 2

Suggested Videos
Part 20 - Angular 2 container and nested components | Text | Slides
Part 21 - Angular component input properties | Text | Slides
Part 22 - Angular component output properties | Text | Slides

In this video we will discuss, what are interfaces and when to use them in Angular.

What is an Interface in TypeScript
If you have experience with any object oriented oriented programming language like C#, Java or C++, then you know an interface is an abstract type. It only contain declarations of properties, methods and events. The implementation for the interface members is provided by a class that implements the interface.



If a class that implements the interface fails to provide implementation for all the interface members, the language compiler raises an error alerting the developer that something has been missed.

In general, an interface defines a contract (i.e the shape or structure of an API), that an implementing class must adhere to. Even in TypeScript we use the interface for the same purpose.



We know TypeScript is a strongly typed language. This means every property we define in a TypeScript class has a type associated with it. Similarly every method parameter and return type has a type. As you know by now, TypeScript has several built-in pre-defined types like string, number, boolean etc.

However, the business objects that we usually create in real-world applications like Employee, Customer, Order, Invoice etc, does not have a pre-defined type. In this case, we can use an interface to create a custom type for our business object.

Let us understand this with an example. We will use the same example we worked with in Part 22 of Angular 2 tutorial.

Notice the below line of code in EmployeeListComponent class. The property "employees" is defined as an array of any type.
employees: any[];

Since we do not have a Type for employee object, we specified the type as any.

There are 2 problems with the above line of code
1. For the object properties in the array we do not get intellisense
angular interface example

2. Since we do not get intellisense, we are prone to making typographical errors and the compiler will not be able to flag them as errors. We will come to know about these errors only at runtime.

Let's create a Type for employee using an interface as shown below. Add a new TypeScript file to the employee folder. Name it employee.ts. Copy and paste the following code.

export interface IEmployee {
    code: string;
    name: string;
    gender: string;
    annualSalary: number;
    dateOfBirth: string;
}

With this IEmployee interface in place, we can now import and use the interface type as the type for "employees" property. The code in EmployeeListComponent class is shown below.

import { IEmployee } from './employee';

export class EmployeeListComponent {
    employees: IEmployee[];
}

Since we have specified a type for the "employees" property, we now get intellisense for the object properties in the array
angular define interface

If we make any typographical errors with the property names, we will get to know these errors right away at compile time.

While we are here, let's discuss some of the concepts related to TypeScript interfaces. Conside the following interface. The code is commented and self-explanatory.

export interface IEmployee {
    code: string;
    name: string;
    gender: string;
    annualSalary: number;
    dateOfBirth: string;
    // To make a property optional use a ?
    // A class that implements this interface need
    // not provide implementation for this property
    department?: string;

    computeMonthlySalary(annualSalary: number): number;
}

export class Employee implements IEmployee {
    // All the interface mandatory properties are defined  
    public code: string;
    public name: string;
    public gender: string;
    public annualSalary: number;
    public dateOfBirth: string;

    // The above class properties are then initialized
    // using the constructor parameters. To do something
    // like this, TypeScript has a shorthand syntax which
    // reduces the amount of code we have to write
    constructor(code: string, name: string, gender: string,
        annualSalary: number, dateOfBirth: string) {
        this.code = code;
        this.name = name;
        this.gender = gender;
        this.annualSalary = annualSalary;
        this.dateOfBirth = dateOfBirth;
    }

    // Implementation of the interface method
    computeMonthlySalary(annualSalary: number): number {
        return annualSalary / 12;
    }
}

Here is the shorthand syntax to initialise class properties with constructor parameters

export interface IEmployee {
    code: string;
    name: string;
    gender: string;
    annualSalary: number;
    dateOfBirth: string;
}

export class Employee implements IEmployee {

    constructor(public code: string, public name: string, public gender: string,
        public annualSalary: number, public dateOfBirth: string) {
    }

}

The above shorthand syntax is not limited to public class properties. We can also use it with private class properties. In the example below we have 2 private properties (firstName & lastName) which are initialised with class constructor.

export class Employee {
    private firstName: string;
    private lastName: string;

    constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

We can rewrite the above code using shorthand syntax as shown below. In both the cases the generated JavaScript code is the same.

export class Employee {
    constructor(private firstName: string, private lastName: string) {
    }
}

Interfaces in TypeScript
  1. Use interface keyword to create an interface
  2. It is common to prefix the interface name with capital letter "I". However, some interfaces in Angular does not have the prefix "I". For example, OnInit interface
  3. Interface members are public by default and does not require explicit access modifiers. It is a compile time error to include an explicit access modifier. You will see an error message like - public modifier cannot appear on a type member.
  4. A class that implements an interface must provide implementation for all the interface members unless the members are marked as optional using the ? operator
  5. Use the implements keyword to make a class implement an interface
  6. TypeScript interfaces exist for developer convenience and are not used by Angular at runtime. During transpilation, no JavaScript code is generated for an interface. It is only used by Typescript for type checking during development.
  7. To reduce the amount of code you have to write, consider using short-hand syntax to initialise class properties with constructor parameters
Video Link


Angular component lifecycle hooks

Suggested Videos
Part 21 - Angular component input properties | Text | Slides
Part 22 - Angular component output properties | Text | Slides
Part 23 - Interfaces in Angular 2 | Text | Slides



In this video we will discuss Angular component lifecycle hooks.

A component has a lifecycle managed by Angular. Angular
  1. Creates the component
  2. Renders the component
  3. Creates and renders the component children
  4. Checks when the component data-bound properties change, and 
  5. Destroys the component before removing it from the DOM


To tap into and react when these life cycle events occur, angular offers several lifecycle hooks as shown in the image below. 
angular component lifecycle hooks

The 3 most commonly used hooks are
Life Cycle Hook Purpose
ngOnChanges Executes, every time the value of an input property changes. The hook method receives a SimpleChanges object containing current and previous property values. This is called before ngOnInit
ngOnInit Executes after the constructor and after ngOnChange hook for the first time. It is most commonly used for component initialisation and retrieving data from a database
ngOnDestroy Executes just before angular destroys the component and generally used for performing cleanup

There are 3 simple steps to use the Life Cycle Hooks
Step 1 : Import the Life Cycle Hook interface. For example, to use ngOnInit() life cycle hook, import OnInit interface.

import { OnInit } from '@angular/core';

Step 2 : Make the component class implement the Life Cycle Hook interface, using the implements keyword as shown below. This step is optional, but good to have so you will get editor support and flags errors at compile time if you incorrectly implement the interface method or make any typographical errors.

export class SimpleComponent implements OnInit { }

Step 3 : Write the implementation code for the life cycle interface method. Each interface has a single hook method whose name is the interface name prefixed with ng.

ngOnInit() {
    console.log('OnInit Life Cycle Hook');
}

Let's understand ngOnChanges life cycle hook with a simple example. Here is what we want to do. As soon as the user starts typing into the text box, we want to capture the current and previous value and log it to the browser console as shown below. We can very easily achieve this by using the ngOnChanges life cycle hook.
ngonchanges example angular 2

ngOnChanges, is called every time the value of an input property of a component changes. So first let's create a SimpleComponent with an input property as shown below. We will continue with the example we worked with in our previous video. Add a new folder in the App folder and name it Others. Add a new TypeScript file to this folder and name it - simple.component.ts. Copy and paste the following code which is commented and self explanatory.

// Step 1 : Import OnChanges and SimpleChanges
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';

// The selector "simple" will be used as the directive
// where we want to use this component. Notice we are
// also using the simpleInput property with interpolation
// to display the value it receives from the parent
// component
@Component({
    selector: 'simple',
    template: `You entered : {{simpleInput}}`
})
// Step 2 : Implement OnChanges Life Cycle Hook interface
export class SimpleComponent implements OnChanges {
    // Input property. As and when this property changes
    // ngOnChanges life cycle hook method is called
    @Input() simpleInput: string;

    // Step 3 : Implementation for the hook method
    // This code logs the current and previous value
    // to the console.
    ngOnChanges(changes: SimpleChanges) {
        for (let propertyName in changes) {
            let change = changes[propertyName];
            let current = JSON.stringify(change.currentValue);
            let previous = JSON.stringify(change.previousValue);
            console.log(propertyName + ': currentValue = '
                + current + ', previousValue = ' + previous);
            // The above line can be rewritten using
            // placeholder syntax as shown below
            // console.log(`${propertyName}: currentValue
            // = ${current }, previousValue = ${previous }`);
        }
    }
}

Now copy and paste the following code in our root component - app.component.ts

import { Component } from '@angular/core';

// Notice we have placed the text box in this root component
// To keep the value in the textbox and the component property
// value "userText" in sync we are using 2 way data binding
// We have also bound userText property of this component
// to the input property of the SimpleComponent
@Component({
    selector: 'my-app',
    template: `Your Text : <input type='text' [(ngModel)]='userText'/>
               <br/><br/>
               <simple [simpleInput]='userText'></simple>
              `
})
export class AppComponent {
    userText: string = 'Pragim';
}

Please note : Do not forget to import and declare SimpleComponent in the root module - app.module.ts

At this point run the application and launch browser developer tools. As you start typing into the text box, the changes are logged to the console by the ngOnChanges life cycle hook method.

The steps for implementing the other component life cycle hook methods are very similar.

Video Link


Angular services tutorial

Suggested Videos
Part 22 - Angular component output properties | Text | Slides
Part 23 - Interfaces in Angular 2 | Text | Slides
Part 24 - Angular component lifecycle hooks | Text | Slides

In this video we will discuss
  • Why we need a service in Angular
  • Creating a service in Angular
  • Injecting and using the service
  • Difference between constructor and ngOnInit


Why do we need a service in Angular
A service in Angular is generally used when you need to reuse data or logic across multiple components. Anytime you see logic or data-access duplicated across multiple components, think about refactoring that piece of logic or data-access code into a service. Using a service ensures we are not violating one of the Software principles - DRY ((Don't repeat yourself). The logic or data access is implemented once in a service, and the service can be used across all the components in our application. 



Without the service you would have to repeat your code in each component. Imagine the overhead in terms of time and effort required to develop, debug, test and maintain the duplicated code across multiple places instead of having that duplicated code at one central place like a service and reusing that service where required.

Creating a service in Angular : We will be working with the same example that we have been working with so far in this video series. Add a new TypeScript file to the "employee" folder and name it employee.service.ts. Copy and paste the following code. At the moment we have the data hard-coded in the service method. In a later video we will discuss retrieving data from a remote server using HTTP.

import { Injectable } from '@angular/core';
import { IEmployee } from './employee';

// The @Injectable() decorator is used to inject other dependencies
// into this service. As our service does not have any dependencies
// at the moment, we may remove the @Injectable() decorator and the
// service works exactly the same way. However, Angular recomends
// to always use @Injectable() decorator to ensures consistency
@Injectable()
export class EmployeeService {
    getEmployees(): IEmployee[] {
        return [
            {
                code: 'emp101', name: 'Tom', gender: 'Male',
                annualSalary: 5500, dateOfBirth: '6/25/1988'
            },
            {
                code: 'emp102', name: 'Alex', gender: 'Male',
                annualSalary: 5700.95, dateOfBirth: '9/6/1982'
            },
            {
                code: 'emp103', name: 'Mike', gender: 'Male',
                annualSalary: 5900, dateOfBirth: '12/8/1979'
            },
            {
                code: 'emp104', name: 'Mary', gender: 'Female',
                annualSalary: 6500.826, dateOfBirth: '10/14/1980'
            },
            {
                code: 'emp105', name: 'Nancy', gender: 'Female',
                annualSalary: 6700.826, dateOfBirth: '12/15/1982'
            },
            {
                code: 'emp106', name: 'Steve', gender: 'Male',
                annualSalary: 7700.481, dateOfBirth: '11/18/1979'
            },
        ];
    }
}

Injecting and using the service : We need the employee service we created above in EmployeeListComponent. So let's import, register and use the Employee service in EmployeeListComponent as shown below. 

// Import OnInit Life Cycle Hook interface
import { Component, OnInit } from '@angular/core';
import { IEmployee } from './employee';
// Import EmployeeService
import { EmployeeService } from './employee.service';

@Component({
    selector: 'list-employee',
    templateUrl: 'app/employee/employeeList.component.html',
    styleUrls: ['app/employee/employeeList.component.css'],
    // Register EmployeeService in this component by
    // declaring it in the providers array
    providers: [EmployeeService]
})
// Make the class implement OnInit interface
export class EmployeeListComponent implements OnInit {
    employees: IEmployee[];

    selectedEmployeeCountRadioButton: string = 'All';

    // Inject EmployeeService using the constructor
    // The private variable _employeeService which points to
    // EmployeeService singelton instance is then available
    // throughout this class
    constructor(private _employeeService: EmployeeService) {
    }

    // In ngOnInit() life cycle hook call the getEmployees()
    // service method of EmployeeService using the private
    // variable _employeeService
    ngOnInit() {
        this.employees = this._employeeService.getEmployees();
    }

    getTotalEmployeesCount(): number {
        return this.employees.length;
    }

    getTotalMaleEmployeesCount(): number {
        return this.employees
            .filter(e => e.gender === 'Male').length;
    }

    getTotalFemaleEmployeesCount(): number {
        return this.employees.filter(e => e.gender === 'Female').length;
    }

    onEmployeeCountRadioButtonChange(selectedRadioButtonValue: string): void {
        this.selectedEmployeeCountRadioButton = selectedRadioButtonValue;
    }
}

Please do not forget to use the EmployeeListComponent selector (list-employee) as a directive in the root component - AppComponent (app.component.ts) as shown below.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<list-employee></list-employee>`
})
export class AppComponent {
}

At this point, run the application and notice it works exactly the same way as before. 

The following line of code which calls the service, can be placed even in the constructor and the application still works exactly the same way as before. So what is the difference between a constructor and ngOnInit life cycle hook, and when to use one over the other.

this.employees = this._employeeService.getEmployees();

Difference between constructor and ngOnInit
A class constructor is automatically called when an instance of the class is created. It is generally used to initialise the fields of the class and it's sub classes. 

ngOnInit is a life cycle hook method provided by Angular. ngOnInit is called after the constructor and is generally used to perform tasks related to Angular bindings. For example, ngOnInit is the right place to call a service method to fetch data from a remote server. We can also do the same using a class constructor, but the general rule of thumb is, tasks that are time consuming should use ngOnInit instead of the constructor. As fetching data from a remote server is time consuming, the better place for calling the service method is ngOnInit.

So coming back to our example, the dependency injection is done using the class constructor and the actual service method call is issued from ngOnInit life cycle hook as shown below

constructor(private _employeeService: EmployeeService) { }

ngOnInit() {
    this.employees = this._employeeService.getEmployees();
}

In our next video we will discuss retrieving data from a remote server using HTTP.

Video Link


Angular and ASP.NET Web API

Suggested Videos
Part 23 - Interfaces in Angular 2 | Text | Slides
Part 24 - Angular component lifecycle hooks | Text | Slides
Part 25 - Angular services tutorial | Text | Slides

In this video we will discuss creating ASP.NET Web API service that retrieves employees data from a database table. In our next video we will discuss, how to call this ASP.NET Web API service using Angular



Step 1 : Execute the following SQL Script using SQL Server Management studio. This script creates
  • EmployeeDB database
  • Creates the Employees table and populate it with sample data


Create Database EmployeeDB
Go

Use EmployeeDB
Go

Create table Employees
(
     code nvarchar(50) primary key,
     name nvarchar(50),
     gender nvarchar(50),
     annualSalary decimal(18,3),
     dateOfBirth nvarchar(50)
)
Go

Insert into Employees values ('emp101', 'Tom', 'Male', 5500, '6/25/1988')
Insert into Employees values ('emp102', 'Alex', 'Male', 5700.95, '9/6/1982')
Insert into Employees values ('emp103', 'Mike', 'Male', 5900, '12/8/1979')
Insert into Employees values ('emp104', 'Mary', 'Female', 6500.826, '10/14/1980')
Insert into Employees values ('emp105', 'Nancy', 'Female', 6700.826, '12/15/1982')
Insert into Employees values ('emp106', 'Steve', 'Male', 7700.481, '11/18/1979')

Step 2 : To keep Angular and Web API projects separate, let's create a new project for our Web API Service. Right click on "Angular2Demo" solution in the Solution Explorer and select Add - New Project.

Step 3 : In the Add New Project window
  1. Select "Visual C#" under "Installed - Templates"
  2. From the middle pane select, ASP.NET Web Application
  3. Name the project "EmployeeWebAPIService" and click "OK" angular and asp.net web api
Step 4 : On the next window, select "Web API" and click "OK". At this point you should have the Web API project created.

Step 5 : Add ADO.NET Entity Data Model to retrieve data from the database. Right click on "EmployeeWebAPIService" project and select Add - New Item
  1. In the "Add New Item" window
  2. Select "Data" from the left pane
  3. Select ADO.NET Entity Data Model from the middle pane
  4. In the Name text box, type EmployeeDataModel and click Add angularjs 2 asp net entity framework example
Step 6 : On the Entity Data Model Wizard, select "EF Designer from database" option and click next

Step 7 : On the next screen, click "New Connection" button

Step 8 : On "Connection Properties" window, set
  1. Server Name = (local)
  2. Authentication = Windows Authentication
  3. Select or enter a database name = EmployeeDB
  4. Click OK and then click Next
Step 9 : On the nex screen, select "Employees" table and click Finish.

Adding Web API Controller

1. Right click on the Controllers folder in EmployeeWebAPIService project and select Add - Controller

2. Select "Web API 2 Controller - Empty" and click "Add"

3. On the next screen set the Controller Name = EmployeesController and click Add

4. Copy and paste the following code in EmployeesController.cs

using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace EmployeeWebAPIService.Controllers
{
    public class EmployeesController : ApiController
    {
        public IEnumerable<Employee> Get()
        {
            using(EmployeeDBEntities entities = new EmployeeDBEntities())
            {
                return entities.Employees.ToList();
            }
        }

        public Employee Get(string code)
        {
            using (EmployeeDBEntities entities = new EmployeeDBEntities())
            {
                return entities.Employees.FirstOrDefault(e => e.code == code);
            }
        }
    }
}

At this point when you navigate to /api/employees you will see all the employees as expected. However, when you navigate to /api/employees/emp101, we expect to see employee whose employee code is emp101, but we still see the list of all employees. 
This is because the parameter name for the Get() method in EmployeesController is "code"

public Employee Get(string code)
{
    using (EmployeeDBEntities entities = new EmployeeDBEntities())
    {
        return entities.Employees.FirstOrDefault(e => e.code == code);
    }
}

but in the default Web API route in WebApiConfig.cs file the parameter name is {id}. Change this to "code" as shown below

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{code}",
    defaults: new { code = RouteParameter.Optional }
);

With this change if we navigate to /api/employees/emp101 we see just that employee whose employee code is "emp101"

In our next video we will discuss, how to call this ASP.NET Web API service using Angular

Video Link


Angular 2 http service tutorial

Suggested Videos
Part 24 - Angular component lifecycle hooks | Text | Slides
Part 25 - Angular services tutorial | Text | Slides
Part 26 - Angular and ASP.NET Web API | Text | Slides

In this video we will discuss 
How to call ASP.NET Web API service using Angular 2 http service. Though this example demonstrates calling ASP.NET Web API service, we can use this same approach to call any web service built using any server side technology. We will also briefly discuss Observable pattern



In our previous video we have created ASP.NET EmployeeWebAPIService. Here are the steps to call the Web API service using the Angular builtin http service.



Step 1 - Import the angular HTTP module : The first step is to import HttpModule which is present in a separate javascript file - @angular/http. After the HttpModule is imported, include it in the imports array of the NgModule() decorator of our root module "AppModule" which is in "app.module.ts" file. With this change we can now start using the angular built-in http service throughout our application to access web services over HTTP.

import { HttpModule } from '@angular/http';

@NgModule({
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule],
    declarations: [
        AppComponent,
        EmployeeComponent,
        EmployeeListComponent,
        EmployeeTitlePipe,
        EmployeeCountComponent,
        SimpleComponent
    ],
    bootstrap: [AppComponent]
})

export class AppModule { }

Step 2 - Modify angular EmployeeService to issue a GET request using the builtin http service : The angular EmployeeService is in employee.service.ts file. 
  • Use the EmployeeService class constructor to inject Angular Http service. The injected http service can then be used anywhere in this class to call a web service over http. 
  • Since this Angular EmployeeService class has an injected dependency, @Injectable() decorator is required on this class. If there are no injectable dependencies then we may omit the @Injectable() decorator, but angular strongly recomends to use the @Injectable() decorator irrespective of there are injectible dependencies or not for consistency and future proof.
  • Notice in the getEmployees() method, we are using the get() method of the angular http service to issue a get request over http. If you right click on get() method and go to it's definition you will notice that this method return Observable<Response>.
  • Observable<Response> is not that useful to us, so we have set the return type of getEmployees() method to Observable<IEmployee[]> 
  • To convert Observable<Response> to Observable<IEmployee[]> we are using the map operator provided by rxjs.
  • At the moment, we are not handling exceptions. We will discuss how to handle exceptions in our upcoming videos.
What is an Observable 
  • Observable is an asynchronous pattern. In the Observable pattern we have an Observable and an Observer. Observer observes the Observable. In many implementations an Observer is also called as a Subscriber.
  • An Observable can have many Observers (also called Subscribers).
  • Observable emits items or notifications over time to which an Observer (also called Subscriber) can subscribe.
  • When a subscriber subscribes to an Observable, the subscriber also specifies a callback function.
  • This subscriber callback function is notified as and when the Observable emits items or notifications.
  • Within this callback function we write code to handle data itmes or notifications received from the Observable.
angular 2 observable example

import { Injectable } from '@angular/core';
import { IEmployee } from './employee';
// Import Http & Response from angular HTTP module
import { Http, Response } from '@angular/http';
// Import Observable from rxjs/Observable
import { Observable } from 'rxjs/Observable';
// Import the map operator
import 'rxjs/add/operator/map';

@Injectable()
export class EmployeeService {

    // Inject Angular http service
    constructor(private _http: Http) { }

    // Notice the method return type is Observable<IEmployee[]>
    getEmployees(): Observable<IEmployee[]> {
        // To convert Observable<Response> to Observable<IEmployee[]>
        // we are using the map operator
        return this._http.get('http://localhost:24535/api/employees')
            .map((response: Response) => <IEmployee[]>response.json());
    }
}

Step 3 - Subscribe to the Observable returned by angular EmployeeService : EmployeeListComponent needs the employees data returned by the service. So in the ngOnInit() method of "employeeList.component.ts" use the subscribe method as shown below.

ngOnInit() {
    this._employeeService.getEmployees()
        .subscribe(employeesData => this.employees = employeesData);
}

Notice to the subscribe() function we are passing an other arrow function as a parameter. This arrow function is called when the Observable emits an item. In our case the Observable emits an array of IEmployee objects. employeesData parameter receives the array of IEmployee objects, which we are then using to initialise employees property of the EmployeeListComponent class. We can specify upto 3 callback functions as parameters to the subscribe() method as shown below.

Callback Method Purpose
onNext The Observable calls this method whenever the Observable emits an item. The emitted item is passed as a parameter to this method
onError The Observable calls this method if there is an error
onCompleted The Observable calls this method after it has emitted all items, i.e after it has called onNext for the final time

At the moment, in our example, we only have used onNext() callback method. In our upcoming videos we will discuss using onError() method to handle exceptions. Using Visual Studio intellisense you can see these 3 callback functions of the subscribe() method.

At this point, run the application. The data may not display and you see the following error in browser developer tools.
Cannot read property 'length' of undefined - at EmployeeListComponent.getTotalEmployeesCount

Reson for the above error : Consider this HTML in employeeList.component.html. Notice we are binding to the input properties (all, male and female) of <employee-count> component.

<employee-count [all]="getTotalEmployeesCount()"
                [male]="getTotalMaleEmployeesCount()"
                [female]="getTotalFemaleEmployeesCount()"
                (countRadioButtonSelectionChanged)=
                "onEmployeeCountRadioButtonChange($event)">
</employee-count>

Here is the getTotalEmployeesCount() method which is binded to "all" property of <employee-count> component.

getTotalEmployeesCount(): number {
    return this.employees.length;
}

The Web API call to retrieve is in ngOnInit(). Before the service call can initialise "employees" property of the EmployeeListComponent class, getTotalEmployeesCount() method is trying to access "length" property of "employees" property. "employees" property is still undefined at that point, so we get the error - Cannot read property 'length' of undefined.

ngOnInit() {
    this._employeeService.getEmployees()
        .subscribe(employeesData => this.employees = employeesData);
}

To fix this error use angular structural directive *ngIf as shown below. This will delay the initialization of employee-count component until "employees" property is initialised.

<employee-count *ngIf="employees" [all]="getTotalEmployeesCount()"
                [male]="getTotalMaleEmployeesCount()"
                [female]="getTotalFemaleEmployeesCount()"
                (countRadioButtonSelectionChanged)=
                "onEmployeeCountRadioButtonChange($event)">
</employee-count>

At this point if you run the application, you will see no employees on the web page and in the browser developer tools you will see the following error message
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:12345' is therefore not allowed access.

We get this error because our Angular application and Web API service are in different projects. Because they are present in different projects the port numbers are different. Since the port numbers are different, the request from the angular project to the web api project is a cross domain request which violates the same origin policy and as a result the browser blocks the request for security reasons. 

To learn more about same origin policy and Cross-origin resource sharing please watch Parts 14 and 15 from ASP.NET Web API tutorial

To fix this error include the following setting in web.config file of the Web API project
<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
      <add name="Access-Control-Allow-Headers" value="Content-Type" />
      <add name="Access-Control-Allow-Methods"
           value="GET, POST, PUT, DELETE, OPTIONS" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Here is the complete employeeList.component.html

<employee-count *ngIf="employees" [all]="getTotalEmployeesCount()"
                [male]="getTotalMaleEmployeesCount()"
                [female]="getTotalFemaleEmployeesCount()"
                (countRadioButtonSelectionChanged)=
                "onEmployeeCountRadioButtonChange($event)">
</employee-count>
<br />
<br />
<table>
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Gender</th>
            <th>Annual Salary</th>
            <th>Date of Birth</th>
        </tr>
    </thead>
    <tbody>
        <ng-container *ngFor="let employee of employees;">
            <tr *ngIf="selectedEmployeeCountRadioButton=='All' ||
                           selectedEmployeeCountRadioButton==employee.gender">
                <td>{{employee.code | uppercase}}</td>
                <td>{{employee.name | employeeTitle:employee.gender }}</td>
                <td>{{employee.gender}}</td>
                <td>{{employee.annualSalary | currency:'USD':true:'1.3-3'}}</td>
                <td>{{employee.dateOfBirth | date:'dd/MM/y'}}</td>
            </tr>
        </ng-container>
        <!--If the web service takes time to return data, the message in this <tr>
        is displayed. When the service call returns this message disappears
        and the employees data is displayed-->
        <tr *ngIf="!employees">
            <td colspan="5">
                Loading data. Please wait...
            </td>
        </tr>
        <!--This message is displayed if the web services does not return any data-->
        <tr *ngIf="employees && employees.length==0">
            <td colspan="5">
                No employee records to display
            </td>
        </tr>
    </tbody>
</table>

We can also use promises instead of Observables. We will discuss using promises in our upcoming videos.

Video Link


Angular 2 http error handling

Suggested Videos
Part 25 - Angular services tutorial | Text | Slides
Part 26 - Angular and ASP.NET Web API | Text | Slides
Part 27 - Angular 2 http service tutorial | Text | Slides

In this video we will discuss error handling in Angular. This is continuation to Part 27. Please watch Part 27 from Angular 2 tutorial before proceeding. 



When using http, to call a web service, errors may occur. When they do occur we want to handle these errors.



1. We use the catch operator to catch any exceptions that occur.

2. Before we use the catch operator we have to import it, just like how we imported map operator.
import 'rxjs/add/operator/catch';

3. The catch operator can then be chained to the map operator.
return this._http.get('http://localhost:24535/api/employeess')
    .map((response: Response) => <IEmployee[]>response.json())
    .catch(this.handleError);

4. To the catch operator we are passing another method (handleError). This handleError() method is called when there is an exception.

handleError(error: Response) {
    console.error(error);
    return Observable.throw(error);
}

5. In a real world application we may pass the error to a logging service to log the error to a file or a database table, so the developers can see these errors and fix them if required.

6. In our case, to keep things simple we are logging to the browser console. 

7. Since we want the error message color to be red so it stands out, we are using console.error() method instead of console.log() method to log the error to the browser console.

8. After we log the error, we are throwing the error back, so the components that use this service are notified about the error condition, so they can display a meaningful error message to the user.

9. To use throw, we will have to import it from rxjs
import 'rxjs/add/Observable/throw';

Here is the complete code in employee.service.ts 

import { Injectable } from '@angular/core';
import { IEmployee } from './employee';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/Observable/throw';

@Injectable()
export class EmployeeService {

    constructor(private _http: Http) { }

    getEmployees(): Observable<IEmployee[]> {
        return this._http.get('http://localhost:24535/api/employees')
            .map((response: Response) => <IEmployee[]>response.json())
            .catch(this.handleError);
    }

    handleError(error: Response) {
        console.error(error);
        return Observable.throw(error);
    }
}

We are calling this service from EmployeeListComponent. So we need to handle the error we have thrown from the service and display a meaningful message to the user. We are subscribing to the service, in ngOnInit() life cycle hook of EmployeeListComponent.

Notice there are 2 parameters to the subscribe() function. Both these parameters are arrow functions. The first arrow function is called when the Observable successfully emits an item. The second arrow function is called, when there is an error.


ngOnInit() {
    this._employeeService.getEmployees()
        .subscribe(
        employeesData => this.employees = employeesData,
        error => {
            console.error(error);
            this.statusMessage = 'Problem with the service. Please try again after sometime';
        });
}

Here is the complete code in employeeList.component.ts : Notice the code that is relevant to exception handling is commented and self-explanatory

import { Component, OnInit } from '@angular/core';
import { IEmployee } from './employee';
import { EmployeeService } from './employee.service';

@Component({
    selector: 'list-employee',
    templateUrl: 'app/employee/employeeList.component.html',
    styleUrls: ['app/employee/employeeList.component.css'],
    providers: [EmployeeService]
})

export class EmployeeListComponent implements OnInit {
    employees: IEmployee[];

    // The view template will bind to this property to display
    // "Loading data. Please wait..." message when the data is
    // being loaded. If there is an error the second arrow
    // function in the subscribe method sets this property to
    // "Problem with the service. Please try again after sometime"
    statusMessage: string = 'Loading data. Please wait...';

    selectedEmployeeCountRadioButton: string = 'All';

    constructor(private _employeeService: EmployeeService) {

    }

    ngOnInit() {
        // The second arrow function sets the statusMessage property
        // to a meaningful message that can be displayed to the user
        this._employeeService.getEmployees()
            .subscribe(
            employeesData => this.employees = employeesData,
            error => {
                this.statusMessage =
                    'Problem with the service. Please try again after sometime';
            });
    }

    getTotalEmployeesCount(): number {
        return this.employees.length;
    }

    getTotalMaleEmployeesCount(): number {
        return this.employees
            .filter(e => e.gender === 'Male').length;
    }

    getTotalFemaleEmployeesCount(): number {
        return this.employees.filter(e => e.gender === 'Female').length;
    }

    onEmployeeCountRadioButtonChange(selectedRadioButtonValue: string): void {
        this.selectedEmployeeCountRadioButton = selectedRadioButtonValue;
    }
}

At this point run the application, and notice since we do not have any errors, that data is loaded as expected. Now let's introduce an error. In employee.component.ts file 

Change the url from 
http://localhost:24535/api/employees

To (Notice the extra "s" at the end)
http://localhost:24535/api/employeess

At this point when you reload the page in the browser, you will see the message "Loading data. Please wait...", but the data never loads. 
Angular 2 http error handling

Now launch browser developer tools and you will see the error message logged to the console by the service.
angular 2 observable error handling

This message - "Loading data. Please wait..." is misleading in this case. Instead we should be displaying a meaningful message like - "Problem with the service. Please try again after sometime".

To do this in the view template of EmployeeListComponent (employeeList.component.html) bind to statusMessage property of the EmployeeListComponent class as shown below.

<tr *ngIf="!employees">
    <td colspan="5">
        {{statusMessage}}
    </td>
</tr>

With the above change, while the service is busy retrieving data, we see the message "Loading data. Please wait..." and if there is an error we see the message "Problem with the service. Please try again after sometime"

If you comment the following import statement in employee.service.ts, the exception handling still works as expected.
import 'rxjs/add/Observable/throw';

However, without the above import statement in employee.service.ts file, if you try to log the error object to the console in ngOnInit() method of EmployeeListComponent as shown below, the logging does not work as expected.

ngOnInit() {
    this._employeeService.getEmployees()
        .subscribe(
        employeesData => this.employees = employeesData,
        error => {
            this.statusMessage =
                'Problem with the service. Please try again after sometime';
            // Notice here we are logging the error to the browser console
            console.error(error);
        });
}

With the above change notice the second error message logged to the console. You will see a message stating - observable_1.observable.throw is not a function, which is not the error message we expected. Angular is complaining that it cannot find throw.
observable_1.observable.throw is not a function

If you uncomment the import statement in employee.service.ts file, then we see the error message we expect.

Video Link


Using Bootstrap with Angular 2

Suggested Videos
Part 26 - Angular and ASP.NET Web API | Text | Slides
Part 27 - Angular 2 http service tutorial | Text | Slides
Part 28 - Angular 2 http error handling | Text | Slides

In this video we will discuss
1. How to install and use Bootstrap with Angular
2. How to enable intellisense for bootstrap  in Visual Studio



How to install and use Bootstrap with Angular : There are several ways to install Bootstrap. One way is by using Node.js command prompt.



Step 1 : Open node.js command prompt window. (Click windows start button, expand Node.js folder and right click on "node.js command prompt" and select "Run as administrator" from the command prompt)
install bootstrap using npm in angular 2

Step 2 : In the command prompt navigate to the folder that contains your angular project and type the following command and press enter key. As Bootstrap has a dependency on jQuery, we are installing jQuery as well.
npm install bootstrap@3 jquery --save
npm command to install bootstrap

This installs both Bootstrap and jQuery for use with our Angular project. Notice from the screenshot below, Bootstrap version 3.3.7 and jQuery version 3.2.1 are installed.
install jquery npm angular 2

The required Bootstrap and jQuery files are copied into the node_modules folder within the project directory.
use bootstrap css with angular

Also, notice package.json file is also automatically updated with both the dependencies (Bootstrap and jQuery)
angular package.json dependencies

Step 3 : Finally in index.html file add the following script and link elements to reference the required CSS and JS files. As you can see, these files are being served from the node_modules folder.

<script src="/node_modules/jquery/dist/jquery.min.js"></script>
<link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="/node_modules/bootstrap/dist/js/bootstrap.min.js"></script>

The problem at the moment is intellisense for Bootstrap CSS classes is not working in index.html, or any of the components html or stylesheet files.
bootstrap intellisense visual studio 2015 not working

How to enable intellisense for bootstrap in Visual Studio : Use the following workaround to enable intellisense for bootstrap in Visual Studio.
Step 1 : In Visual Studio, click to select the Angular project and then click on "Show All Files" icon. You will then see "node_modules" folder.
show all files visual studio 2015

Step 2 : Expand "node_modules" folder. Locate "bootstrap" folder. Right click on it and select "Include In Project" option from the context menu.
visual studio 2015 bootstrap intellisense not working

At this point you should get bootstrap intellisense in index.html and all angular component html files. If you still do not get bootstrap intellisense, please restart Visual Stduio and you will get intellisense.
visual studio bootstrap intellisense not working

As I said before, there are several ways to install bootstrap. One way is by using Node.js command prompt. The other way is by using Visual Stduio NuGet package manager. To install Bootstrap using NuGet package manager follow these steps.

Step 1 : In Visual Studio Solution Explorer, right click on the Angular project and select "Manage NuGet Packages" option from the context menu
visual studio nuget bootstrap

Step 2 : In the "NuGet Package Manager" window
  1. Click on the "Browse" link
  2. In the textbox, type "Bootstrap" and press "enter" key
  3. Click on the first item which says - Bootstrap
  4. Click on the arrow pointing downwards to install
nuget package manager install bootstrap

The required CSS and JS files are placed in Content and Script folders. Finally place the required CSS and JS files in index.html page to start using Bootstrap. If you install Bootstrap using NuGet you don't have to do anything else to get bootstrap intellisense.
bootstrap in visual studio

If you do not want to download bootstrap, you can use their CDN links. You can find the official Bootstrap CDN links at the following page.
http://getbootstrap.com/getting-started/

Besides these 3 ways, there are other ways of installing Bootstrap. Which way to use depends on your project needs.

Video Link


Angular 2 routing tutorial

Suggested Videos
Part 27 - Angular 2 http service tutorial | Text | Slides
Part 28 - Angular 2 http error handling | Text | Slides
Part 29 - Using Bootstrap with Angular 2 | Text | Slides

In this video we will discuss the basics of routing in Angular 2. Routing allows users to navigate from one view to another view.

At the moment, we have EmployeeListComponent in our application. Let's create another simple HomeComponent so we can see how to navigate from HomeComponent to EmployeeListComponent and vice-versa



Creating HomeComponent
1. Right click on the "app" folder and add a new folder. Name it "home". Right click on the "home" folder and add a new TypeScript file. Name it home.component.ts. Copy and paste the following code in it. Notice we have not included the 'selector' property in the @component decorator. The selector is only required if we are going to embed this component inside another component using the selector as a directive. Instead we are going to use the router to navigate to this component.



import { Component } from '@angular/core';

@Component({
    template: '<h1>This is the home page</h1>'
})
export class HomeComponent {
}

2. In the application root module (app.module.ts) import HomeComponent and include it in the declarations array of @NgModule decorator.

import { HomeComponent } from './home/home.component';

@NgModule({
    imports: [BrowserModule, FormsModule, HttpModule],
    declarations: [AppComponent, HomeComponent, ...],
    bootstrap: [AppComponent]
})

export class AppModule { }

If the user tries to navigate to a route that does not exist, we want to route the user to PageNotFoundComponent. So let's create this component as well.

Right click on the "others" folder and add a new TypeScript file. Name it pageNotFound.component.ts. Copy and paste the following code in it.

import { Component } from '@angular/core';

@Component({
    template: '<h1>The page you are looking for does not exist</h1>'
})
export class PageNotFoundComponent {
}

Next, in the application root module (app.module.ts) import PageNotFoundComponent and include it in the declarations array of @NgModule decorator.

import { PageNotFoundComponent } from './Others/pageNotFound.component';

@NgModule({
    imports: [BrowserModule, FormsModule, HttpModule],
    declarations: [AppComponent, PageNotFoundComponent, ...],
    bootstrap: [AppComponent]
})
export class AppModule { }

Here are the steps to implement routing in Angular 2 applications.

Step 1 : Set <base href> in the application host page which is index.html. The <base href> tells the angular router how to compose navigation URLs.

<base href="/src/">

Step 2 : In our angular application root module (app.module.ts), import RouterModule and Routes array and define routes as shown below.

import { RouterModule, Routes } from '@angular/router';

// Routes is an array of Route objects
// Each route maps a URL path to a component
// The 3rd route specifies the route to redirect to if the path
// is empty. In our case we are redirecting to /home
// The 4th route (**) is the wildcard route. This route is used
// if the requested URL doesn't match any other routes already defined
const appRoutes: Routes = [
    { path: 'home', component: HomeComponent },
    { path: 'employees', component: EmployeeListComponent },
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: '**', component: PageNotFoundComponent }
];

// To let the router know about the routes defined above,
// pass "appRoutes" constant to forRoot(appRoutes) method
@NgModule({
    imports: [
        BrowserModule, FormsModule, HttpModule,
        RouterModule.forRoot(appRoutes)
    ],
    declarations: [AppComponent, HomeComponent, …],
    bootstrap: [AppComponent]
})
export class AppModule { }

Important: The order of the routes is very important. When matching routes, Angular router uses first-match wins strategy. So more specific routes should be placed above less specific routes. In the configuration above, routes with a static path are listed first, followed by an empty path route, that matches the default route. The wildcard route comes last because it matches every URL and should be selected only if no other routes are matched first.

Step 3 : Tie the routes to application menu. Modify the root component (app.component.ts) as shown below. The only change we made is in the inline template.
  • We are using Bootstrap nav component to create the menu. We discussed Bootstrap nav component in Part 27 of Bootstrap tutorial.
  • The routerLink directive tells the router where to navigate when the user clicks the link.
  • The routerLinkActive directive is used to add the active bootstrap class to the HTML navigation element whose route matches the active route.
  • The router-outlet directive is used to specify the location where we want the routed component's view template to be displayed.
  • The routerLink, routerLinkActive and router-outlet directives are provided by the RouterModule which we have imported in our application root module.
  • If you forget to specify the router-outlet directive, you will get and error stating - cannot find primary outlet to load component.
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
                    <div style="padding:5px">
                        <ul class="nav nav-tabs">
                            <li routerLinkActive="active">
                                <a routerLink="home">Home</a>
                            </li>
                            <li routerLinkActive="active">
                                <a routerLink="employees">Employees</a>
                            </li>
                        </ul>
                        <br/>
                        <router-outlet></router-outlet>
                    </div>
              `
})
export class AppComponent {
}

Step 4 : Finally in web.config file of our angular application include the following url-rewrite rule to tell IIS how to handle routes. The match url, <match url=".*" />, will rewrite every request. The URL in <action type="Rewrite" url="/src/"/> should match the base href in index.html.

<system.webServer>
  <rewrite>
    <rules>
      <rule name="Angular Routes" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="/src/" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

If you do not have the above url rewrite rule, when you referesh the page you will 404 page not found error.

To use "hash style" urls instead of HTML5 style url's, you just need to make one change in app.module.ts file. Set useHash property to true and pass it to the forRoot() method as shown below.

RouterModule.forRoot(appRoutes, { useHash: true })

If you are using "hash style" routes, we don't need the URL rewrite rule in web.config file.

Video Link


Angular 2 route parameters

Suggested Videos
Part 28 - Angular 2 http error handling | Text | Slides
Part 29 - Using Bootstrap with Angular 2 | Text | Slides
Part 30 - Angular 2 routing tutorial | Text | Slides

In this video we will discuss passing parameters to routes in Angular. This is continuation to Part 30. Please watch Part 30 from Angular 2 tutorial before proceeding.



Let us understand this with an example. We want to make Employee Code on Employee List component clickable.
Angular 2 route parameters



When we click on an Employee code, we want to redirect the user to Employee Component which displays that specific employee details. In the URL we will pass the emploee code as a parameter. So clicking on EMP101 will redirect the user to URL (http://localhost/employees/emp101). The Employee component will then read the parameter value from the URL and retrieves that specific employee details by calling the server side web service.
angular 2 route parameters example

In our previous video we have modified the code in app.module.ts file to use hash style routing. Let's remove useHash property, so we are using HTML5 style routing instead of hash style routing. Notice from the forRoot() method I have removed useHash property.
RouterModule.forRoot(appRoutes)

For HTML5 routing to work correctly, uncomment the following URL rewrite rule in web.config file of our Angular application.
<system.webServer>
  <rewrite>
    <rules>
      <rule name="Angular Routes" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="/src/" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

In the root application module (app.module.ts), include the following route. When the user navigates to a URL like (http://localhost:12345/employees/EMP101), we want to display EmployeeComponent. Notice the code parameter specified using colon (:).
{ path: 'employees/:code', component: EmployeeComponent }

Include the above route in appRoutes collection in app.module.ts file as shown below. Remember the order of the routes matter.

const appRoutes: Routes = [
    { path: 'home', component: HomeComponent },
    { path: 'employees', component: EmployeeListComponent },
    { path: 'employees/:code', component: EmployeeComponent },
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: '**', component: PageNotFoundComponent }
];

Next, in EmployeeListComponent, modify the <td> element that displays employee code to bind it to the route we created above using the routerLink directive as shown below. 

<td>
    <a [routerLink]="['/employees',employee.code]">
        {{employee.code | uppercase}}
    </a>

</td>

Explanation of the above code:
  • Notice in this example we are binding routerLink directive to an array.
  • This array is called link parameters array.
  • The first element in the array is the path of the route to the destination component.
  • The second element in the array is the route parameter, in our case the employee code.
In the Angular EmployeeService (employee.service.ts), introduce the following getEmployeeByCode() method. 

getEmployeeByCode(empCode: string): Observable<IEmployee> {
    return this._http.get("http://localhost:31324/api/employees/" + empCode)
        .map((response: Response) => <IEmployee>response.json())
        .catch(this.handleError);
}

Explanation of the above code:
  • This method takes employee code as a parameter and returns that employee object (IEmployee). 
  • This method issues a GET request to the Web API service. 
  • Once the Web API service returns the employee object, this method maps it to IEmployee type and returns it.
In one of our previous videos we have created EmployeeComponent to display employee details. When we created this component, we have hard coded employee data in the component itself. Now let's modify it
  • To retrieve employee details by calling the Angular EmployeeService method getEmployeeByCode() we created above.
  • This method calls the server side Web API service which retrieves that specific employee details from the database.
  • The employee code parameter is in the URL
  • To retrieve the parameter from the URL we are using the ActivatedRoute service provided by Angular 
  • Since ActivatedRoute is provided as a service inject it into the constructor just like how we have injected EmployeeService
employee.component.ts

import { Component, OnInit } from '@angular/core';
import { IEmployee } from './employee';
import { EmployeeService } from './employee.service';
import { ActivatedRoute } from '@angular/router';

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html',
    styleUrls: ['app/employee/employee.component.css']
})
export class EmployeeComponent implements OnInit {
    employee: IEmployee;
    statusMessage: string = 'Loading data. Please wait...';

    constructor(private _employeeService: EmployeeService,
        private _activatedRoute: ActivatedRoute) { }

    ngOnInit() {
        let empCode: string = this._activatedRoute.snapshot.params['code'];
        this._employeeService.getEmployeeByCode(empCode)
            .subscribe((employeeData) => {
                if (employeeData == null) {
                    this.statusMessage =
                        'Employee with the specified Employee Code does not exist';
                }
                else {
                    this.employee = employeeData;
                }
            },
            (error) => {
                this.statusMessage =
                    'Problem with the service. Please try again after sometime';
                console.error(error);
            });
    }
}

employee.component.html

<table *ngIf="employee">
    <thead>
        <tr>
            <th colspan="2">
                Employee Details
            </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Employee Code</td>
            <td>{{employee.code}}</td>
        </tr>
        <tr>
            <td>Name</td>
            <td>{{employee.name}}</td>
        </tr>
        <tr>
            <td>Gender</td>
            <td>{{employee.gender}}</td>
        </tr>
        <tr>
            <td>Annual Salary</td>
            <td>{{employee.annualSalary}}</td>
        </tr>
        <tr>
            <td>Date of Birth</td>
            <td>{{employee.dateOfBirth}}</td>
        </tr>
    </tbody>
</table>
<div *ngIf="!employee">
    {{statusMessage}}
</div>

There are different approaches to retrieve route parameters values. We will discuss all the different approaches and when to use what in our upcoming videos.

Since we need EmployeeService both in EmployeeListComponent and EmployeeComponent, let's register it in the root module so we get a singleton instead of multiple instances of the service. 

We will discuss what is a Singleton in Angular and why is it important in our next video. For now, let's remove the EmployeeService registration from EmployeeListComponent by removing the following providers property in employeeList.component.ts file

providers: [EmployeeService]

Now regsiter the EmployeeService in application root module (app.module.ts) by including it in the providers property of @NgModule decorator as shown below

@NgModule({
    imports: [
        BrowserModule,
        OtherSystemModules..
    ],
    declarations: [
        AppComponent,
        OtherComponents..
    ],
    bootstrap: [AppComponent],
    providers: [EmployeeService]
})
export class AppModule { }

Video Link


Angular dependency injection

Suggested Videos
Part 29 - Using Bootstrap with Angular 2 | Text | Slides
Part 30 - Angular 2 routing tutorial | Text | Slides
Part 31 - Angular 2 route parameters | Text | Slides

In this video we will discuss 
1. What is Dependency Injection
2. How dependency injection works in angular



Let us understand Dependency Injection in Angular with an example. Consider this piece of code in EmployeeListComponent.
export class EmployeeListComponent implements OnInit {

    private _employeeService: EmployeeService;

    constructor(_employeeService: EmployeeService) {
        this._employeeService = _employeeService;
    }

    ngOnInit() {
        this._employeeService.getEmployees()
            .subscribe(
            employeesData => this.employees = employeesData,
            error => this.statusMessage = 'Error');
    }

    // Rest of the code
}

  1. In EmployeeListComponent we need an instance of EmployeeService, so we could use that instance to call getEmployees() method of the service which retrieves the list of employees which this component needs.
  2. But if you look at this code, the EmployeeListComponent is not creating an instance of EmployeeService.
  3. We declared a private field _employeeService of type EmployeeService. The constructor also has a parameter _employeeService of type EmployeeService. The constructor is then initializing the private class field _employeeService with it's parameter.
  4. We are then using this private field _employeeService to call the service method getEmployees()
  5. The obvious question that we get at this point is how are we getting an instance of the EmployeeService class.
  6. We know for sure the EmployeeListComponent is not creating the instance of the EmployeeService class.
  7. From looking at the code we can understand that the constructor is provided with an instance of EmployeeService class, and then the constructor is assigning that instance to the private field _employeeService.
  8. At this point, the next question that comes to our mind is who is creating and providing the instance to the constructor.
  9. The answer to this question is the Angular Injector. When an instance of EmployeeListComponent is created, the angular injector creates an instance of the EmployeeService class and provides it to the EmployeeListComponent constructor. The constructor then assigns that instance to the private field _employeeService. We then use this private field _employeeService to call the EmployeeService method getEmployees().
  10. Another question that comes to our mind is - How does the angular injector knows about EmployeeService.
  11. For the Angular injector to be able to create and provide an instance of EmployeeService, we will have to first register the EmployeeService with the Angular Injector. We register a service with the angular injector by using the providers property of @Component decorator or @NgModule decorator.
  12. We already know we decorate an angular component with @Component decorator and an angular module with @NgModule decorator. So this means if we are registering a service using the providers property of the @Component decorator then we are registering the service with an angular injector at the component level. The service is then available to that component and all of it's children. 
  13. On the other hand if we register the service using the providers property of the @NgModule decorator then we are registering the service with an angular injector at the module level which is the root injector. The service registered with the root injector is then available to all the component accross the entire application.
  14. We will discuss these hierarchical injectors in Angular in detail with an example in our upcoming videos.
Now let's quickly recap what we have discussed so far
  • We register a service with the angular injector by using the providers property of @Component decorator or @NgModule decorator.
  • When a component in Angular needs a service instance, it does not explicitly create it. Instead it just specifies it has a dependency on a service and needs an instance of it by including the service as a constructor parameter.
  • When an instance of the component is created, the angular injector creates an instance of the service class and provides it to component constructor.
  • So the component which is dependent on a service instance, receives the instance from an external source rather than creating it itself. This is called Dependency Injection.
Angular dependency injection

What is Dependency Injection
It's a coding pattern in which a class receives its dependencies from an external source rather than creating them itself. 

So if we relate this definition to our example, EmployeeListComponent has a dependency on EmployeeService. The EmployeeListComponent receives the dependency instance (i.e EmployeeService instance) from the the external source (i.e the angular injector) rather than creating the instance itself.
  1. Why should we use Dependency Injection? 
  2. What benefits it provide?
  3. Why can't we explicitly create an instance of the EmployeeService class using the new keyword and use that instance instead in our EmployeeListComponent?
We will answer these questions in our next video.

Video Link


Why dependency injection

Suggested Videos
Part 30 - Angular 2 routing tutorial | Text | Slides
Part 31 - Angular 2 route parameters | Text | Slides
Part 32 - Angular dependency injection | Text | Slides

In this video we will discuss why should we use dependency injection and the benefits it provide. Let us understand this with a very simple example.



Let us say we want to build a Computer. In reality to build a computer we need several objects like processor, ram, hard-disk drive etc. To keep this example simple let's say we just need a processor object to build a computer.



Our Computer and Processor classes are as shown below. Notice at the moment, we are not using dependency injection. To build a Computer we need a Processor object and the Computer class is creating an instance of the Processor class it needs. This is the kind of programming style that most of us are used to and it is easy to understand as well. But there are 3 fundamental problems with this code
  1. This code is difficult to maintain over time
  2. Instances of dependencies created by a class that needs those dependencies are local to the class and cannot share data and logic.
  3. Hard to unit test
export class Computer {

    private processor: Processor;

    constructor() {
        this.processor = new Processor();
    }
}

export class Processor {

    constructor() {
    }

}

Now let us understand why this code is difficult to maintain. Let us say, the Processor class needs to know the speed of the processor to be able to create an instance of it. One way to address this requirement is by passing the processor speed as a parameter to the constructor of the Processor class as shown below.

export class Processor {

    constructor(speed: number) {
    }

}

This change in the Processor class breaks the Computer class. So every time the Processor class changes, the Computer class also needs to be changed. At the moment, the Computer class has only one dependency. In reality it may have many dependencies and those dependencies in turn may have other dependencies. So when any of these dependencies change, the Computer class may also need to be changed. Hence this code is difficult to maintain.

The reason we have this problem is because the Computer class itself is creating the instance of the Processor class. Instead if an external source can create the processor instance and provide it to the computer class, then this problem can be very easily solved and that's exactly what dependency injection does. I have rewritten the above code using dependency injection, DI for short as shown below.

export class Computer {

    private processor: Processor;

    constructor(processor: Processor) {
        this.processor = processor;
    }
}

export class Processor {

    constructor(speed: number) {
    }

}

Notice with DI, the Computer class is not creating the instance of the Processor class itself. Instead we have specified that the Computer class has a dependency on Processor class using the constructor. Now, when we create an instance of the Computer class, an external source i.e the Angular Injector will provide the instance of the Processor class to the Computer class. Since now the the Angular injector is creating the dependency instance, the Computer class need not change when the Processor class changes.

Now, let us understand the second problem - Instances of dependencies created by a class that needs those dependencies are local to the class and cannot share data and logic. The Processor class instance created in the Computer class is local to the Computer class and cannot be shared. Sharing a processor instance does not make that much sense, so let's understand this with another example. 

Let us say we have a service called UserPreferencesService which keeps track of the user preferences like colour, font-size etc. We want this data to be shared with all the other components in our application. Now if we create an instance of this UserPreferenceService class in every component class like we did in the Computer class, the service instance is local to the component in which we have created it and the data cannot be shared with other components. So if we need this UserPreferencesService in 10 different components, we end up creating 10 instances of the service, one for each component. As the service instance is local to the component that has created it, the data that local service instance has cannot be shared by other components. If this does not make sense at the moment, please do not worry, we will discuss it with a working example in our next video.

On the other hand if we use Dependency Injection (DI), the angular injector provides a Singleton i.e a single instance of the service so the data and logic can be shared very easily across all the components.

From unit testing standpoint, it is difficult to mock the processor object, so unit testing Computer class can get complex. In this example, the Computer class has just one dependency (i.e the dependency on the Processor object). 

In a real world application, a given object may have a dependency on several other objects, and those dependencies inturn may have dependencies on other objects. Just imagine, how complicated unit testing can become with all these hierarchies of dependencies if we do not have the ability to mock the dependencies.

With Dependency Injection it is very easy to mock objects when unit testing. This is one of the greatest benefits of DI.

If you are new to unit testing and mocking, it may be difficult for you to understand why unit testing can get difficult and complicated if we do not have the ability to mock dependencies. In our upcoming videos we will discuss unit testing and mocking and it should be much clear at that point.

So in summary DI provides these benefits
  1. Create applications that are easy to write and maintain over time as the application evolves
  2. Easy to share data and functionality as the angular injector provides a Singleton i.e a single instance of the service
  3. Easy to write and maintain unit tests as the dependencies can be mocked
Video Link


Angular singleton service

Suggested Videos
Part 31 - Angular 2 route parameters | Text | Slides
Part 32 - Angular dependency injection | Text | Slides
Part 33 - Why dependency injection | Text | Slides

In our previous video we discussed why should we use dependency injection and the benefits it provides. One of the benefits of dependency injection is that it allows us to share data and functionality easily as the angular injector provides a Singleton i.e a single instance of the service.


So in this videos let us see how we can use Angular services and dependency injection to create a Singleton i.e a single instance of the service which enables us to share data and functionality across multiple components in our application. To better understand this video, please watch our previous video - Why dependency injection.


Create a simple UserPreferencesService. Add a new file to the "employee" folder. Name it "userPreferences.service.ts". Copy and paste the following code

import { Injectable } from '@angular/core';

@Injectable()
export class UserPreferencesService {
    colourPreference: string = 'orange';
}

Notice this service has a single property "colourPreference" which is defaulted to "orange". We want to retrieve and use this colour in both "HomeComponent" and "EmployeeListComponent". Notice the textbox displays the default colour (orange) and background is also set to orange. Also both these components should have the ability to set the "colourPreference" property of the service to a different value using the textbox.

angular 2 service to store data

angular 2 shared service

Modify the code in home.component.ts file as shown below. The code is commented and self-explanatory.

import { Component } from '@angular/core';
import { UserPreferencesService } from '../employee/userPreferences.service';

// Notice the colour property is bound to the textbox using angular two-way
// databinding. We are also using style binding to set the background colour
// of the textbox
@Component({
    template: `
            <h1>This is the home page</h1>
            <div>
                Colour Preference :
                <input type='text' [(ngModel)]='colour' [style.background]="colour"/>
            </div>`
})
export class HomeComponent {

    // Create a private variable to hold an instance of the UserPreferencesService
    private _userPreferencesService: UserPreferencesService;

    // In the constructor we are creating an instance of the UserPreferencesService
    // using the new keyword. So this instance is local to this component and we
    // cannot use it share data with other components. Later we will modify this
    // code to use dependency injection, which creates a Singleton so the colour
    // data can be shared with other components.
    constructor() {
        this._userPreferencesService = new UserPreferencesService();
    }

    // Implement a getter to retrieve the colourPreference value
    // from the service
    get colour(): string {
        return this._userPreferencesService.colourPreference;
    }

    // Implement a setter to change the colourPreference value
    // of the service
    set colour(value: string) {
        this._userPreferencesService.colourPreference = value;
    }
}

Now we need to make similar changes in "employeeList.component.html" and "employeeList.component.ts" files. First make the following change in "employeeList.component.html"

Include a <div> element after the table in the file. These are the similar changes we made in the inline view template of HomeComponent.

<div>
    Colour Preference :
    <input type="text" [(ngModel)]="colour" [style.background]="colour" />
</div>

Now make the following changes in "employeeList.component.ts"
  1. Introduce a private field to hold an instance of UserPreferencesService
  2. In the constructor create a new instance of UserPreferencesService. Again this instance is local to the EmployeeListComponent and cannot be used to share colour data with the other components. We will discuss how to solve this issue shortly using dependency injection.
  3. Finally, introduce a getter and a setter to get and set "colourPreference" property of the UserPreferencesService
import { UserPreferencesService } from './userPreferences.service';

private _userPreferencesService: UserPreferencesService; 
  
constructor(private _employeeService: EmployeeService) {
    this._userPreferencesService = new UserPreferencesService();
}

get colour(): string {
    return this._userPreferencesService.colourPreference;
}

set colour(value: string) {
    this._userPreferencesService.colourPreference = value;
}

Now run the application and notice that on both "HomeComponent" and "EmployeeListComponent" you will see the service colourPreference property default value "orange" displayed in the textbox. The background colour of the textbox is also set to "orange" as expected.

It looks like the "colourPreference" property of the service is being shared by both the components. But that is not true. Since we are using the new keyword to create an instance of the UserPreferencesService, the instance created in each component is local to that component. Let's prove this.

Introduce a constructor in UserPreferencesService. Notice in the constructor we are logging a message to the console stating that a "New Instance of Service Created". Here is the code in "userPreferences.service.ts"

import { Injectable } from '@angular/core';

@Injectable()
export class UserPreferencesService {

    constructor() {
        console.log('New Instance of Service Created');
    }

    colourPreference: string = 'orange';
}

Run the application again and launch browser developer tools and click on the Console tab. Notice in the Console you will see the message - "New Instance of Service Created"

Now click on "Employees" menu. This will take you to EmployeeListComponent. Take another look in the "Console" tab, you will see "New Instance of Service Created" logged second time. So this proves each component is creating an instance that is local to that component and sharing data using these local instances is not possible. 

angular service sharing data

Now let us see what happens when each of the components change the "colourPreference" property value of the UserPreferencesService. Navigate to the "HomeComponent" and type "yellow" in the textbox. Notice the background colour of the textbox is changed to yellow as expected.

angular shared service between components

Now navigate to "EmployeeListcomponent" by clicking on the "Employees" tab. Notice the "colourPreference" property value is still orange. This is beacuse when we navigate to EmployeeListComponent it has created a new local instance of UserPreferencesService and the default value "orange" is being used.

angular 2 service share data between components

At this point navigate back to the HomeComponent, notice the "colourPreference" property value on the HomeComponent is also "orange" now. This is because when we navigated away from the HomeComponent the previous local instance of the UserPreferencesService it has created is destroyed and when came back to the HomeComponent it created another new local instance of the UserPreferencesService and we got it's default colourPreference property value which is orange.

angular service not singleton

So bottom line, because each component is creating a local instance of the UserPreferencesService we are not able to share data i.e we are not able to see the changes made by one component in the other component.

Now let us see how to create a Singleton i.e a single instance of the UserPreferencesService and use that single instance to share data (colourPreference property value) between the 2 components (HomeComponent & EmployeeListComponent) using dependency injection.

Remember the 2 steps to use dependency injection. We discussed these 2 steps in detail in Part 32 of Angular 2 tutorial.

Step 1 : Register the service using the Providers property of @NgModule() decorator in app.module.ts file

import { UserPreferencesService } from './employee/userPreferences.service';

@NgModule({
   providers: [UserPreferencesService]
})
export class AppModule { }

Step 2 : Specify the dependency on UserPreferencesService using the constructor of HomeComponent & EmployeeListComponent.

Modify the HomeComponent class constructor as shown below. Notice now we are using dependency injection, instead of creating a local instance of the UserPreferencesService using the new keyowrd.

export class HomeComponent {

    constructor(private _userPreferencesService: UserPreferencesService) {
    }
}

Along the samelines, modify EmployeeListComponent class as well.

export class EmployeeListComponent implements OnInit {
    // Other code

    constructor(private _employeeService: EmployeeService,
        private _userPreferencesService: UserPreferencesService)
    { }

    // Other code
}

With all these changes in place, run the application one more time and navigate to HomeComponent. Notice we have the default "colourPreference" property value orange. At this point change the colour in the textbox to yellow. Notice the background colour changes to yellow as expected.

angular service single instance

Now navigate to the EmployeeListComponent. Notice we see the yellow colour which the HomeComponent has set. Also notice in the "Console" table of the browser developer tools, this message (New Instance of Service Created) is logged only once when we navigate between HomeComponent and EmployeeListComponent which proves that only a single instance of the service (ie. a singleton) is created. This singleton enables data sharing between both the components. That's how we are able to see the changes made by one component in the other component.

angular service singleton example

So bottom line, with dependency injection it is easy to share data and functionality as the angular injector provides a Singleton i.e a single instance of the service.

Video Link


Angular Injector

Suggested Videos
Part 32 - Angular dependency injection | Text | Slides
Part 33 - Why dependency injection | Text | Slides
Part 34 - Angular singleton service | Text | Slides

In this video we will discuss Angular Injectors. This is continuation to Part 34. Please watch Part 34 from Angular 2 tutorial before proceeding.


In Part 32 of Angular 2 tutorial we discussed what is dependency injection and how it is implemented in Angular. There are 2 simple steps to use dependency injection in Angular. For example, if you have a component that depends on a service and needs an instance of it,

Step 1 : First register the service with the angular injector
Step 2 : Specify a dependency using the constructor of your component class.


With these 2 steps in place, the angular injector will automatically inject an instance of the the service into the component's constructor when an instance of the component is created.

Angular 1 has only one global injector but in Angular 2 we have one injector at the application root level and hierarchical injectors that parallel an application's component tree. This means in Angular 2, we have one root injector plus an injector at every component level as you can see from the diagram below.

angular 2 injector example

If a service is registered with the root injector then that service is available for all components in our entire application including the components in lazy loaded modules. We will discuss lazy loaded modules in a later video in this series.

If a service is registered with the injector at the Application Root component level, then that service is available for all the components in the application except the components in lazy loaded modules.

If a service is registered with a specific component injector, then that service is available for that component and any of it's children. For example, if we register a service with Component X injector, then that service is available for Components X, Y & Z but not for Component A. Similarly if a we register a service with Component A injector, then that service is available only for Component A but not for Components X, Y & Z.

We can register a service with the angular injector using the providers property of @Component decorator or @NgModule decorator.

To register a service with the root injector use providers property of @ngModule decorator of root module (app.module.ts) or any feature module

To register a service with the injector at a component levet use providers property of @Component decorator

Video Link


Angular root injector

Suggested Videos
Part 33 - Why dependency injection | Text | Slides
Part 34 - Angular singleton service | Text | Slides
Part 35 - Angular Injector | Text | Slides

In this video we will discuss the Angular root injector. In our previous video we discussed that, in Angular 2 we have one root injector at the application level plus an injector at every component level as you can see from the diagram below.


Angular root injector


To register a service with the root injector we use providers property of @ngModule decorator and to register a service with the injector at a component level use providers property of @Component decorator.

At the moment in our application we have just one module which is the application root module. In a real world application it is very common to have more than one module. For example, if you are building an HR management system in addition to the root application module (AppModule) we may have feature modules like Employee module, Department Module, Admin Module, Reporting Module etc. 

In our previous video we have used the @NgModule() decorator of the root module to register our service with the root injector. We can also use any of the feature module's @NgModule() decorator to register our service with the root injector. Let's prove this. 

At the moment in our application we do not have any feature modules. So let's create a simple TestModule and then use that module's @NgModule() decorator to register our service with the root injector.

To create a TestModule
1. Add a new TypeScript file to the "app" folder. Name it "test.module.ts"

2. Copy and paste the following code in it. As you can see from the code below creating a module is very similar to creating a component. To create a component, we first create a class, import @Component() decorator and decorate the class with it. 

This makes the TypeScript class an angular component. Along the same lines, to create a module, we first create a class, import @ngModule() decorator and decorate the class with it. This makes the TypeScript class an angular module. So as you can see, Angular provides consistent set of patterns for creating components, pipes, directives and modules. 

Notice, we are registering our UserPreferencesService with the root injector using the @NgModule() decorator of this TestModule.

import { NgModule } from '@angular/core';
import { UserPreferencesService } from './employee/userPreferences.service';

@NgModule({
    providers: [UserPreferencesService]
})
export class TestModule { }

3. Just like how we have imported angular system modules (like BrowserModule,
 FormsModule, HttpModule etc) in our root module(app.module.ts), we need to import the TestModule to be able to use it in our application. So include the required import statement and make the TestModule part of imports array of @NgModule() decorator in the root module (i.e app.module.ts file). 

Finally remove "UserPreferencesService" from the providers property. We have already registered our UserPreferencesService with the root injector using the @NgModule() decorator of the TestModule.

import { TestModule } from './test.module';

@NgModule({
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule,
        TestModule,
        RouterModule.forRoot(appRoutes)
    ],
    declarations: [
        AppComponent,
        EmployeeComponent,
        EmployeeListComponent,
        EmployeeTitlePipe,
        EmployeeCountComponent,
        SimpleComponent,
        HomeComponent,
        PageNotFoundComponent
    ],
    bootstrap: [AppComponent],
    providers: [EmployeeService]
})
export class AppModule { }

With all these changes run the application and test. It works exactly the same way as before. So this proves that we can use any module provider property to register a service with the root injector. It can be a feature module or the root module.

Video Link


Angular router navigate method

Suggested Videos
Part 34 - Angular singleton service | Text | Slides
Part 35 - Angular Injector | Text | Slides
Part 36 - Angular root injector | Text | Slides

In this video we will discuss the use of Angular Router service navigate() method. This method is useful when you want to navigate to another page programmatically.


Let us understand this with an example. Here is what we want to do. On the EmployeeComponent that displays specific employee details, we want to include a Button as shown in the image below. When we click the button we want to redirect the user to EmployeeListComponent.


Angular router navigate method

Step 1 : Include the following HTML markup for the button on employee.component.html. Notice we are using Bootstrap button css classes (btn & btn-primary) to style the button. We are using event binding to bind click event of the button to bind to "onBackButtonClick()" method in the EmployeeComponent class.

<div style="margin-top:5px">
    <input type="button" class="btn btn-primary" value="Back to Employees List"
           (click)="onBackButtonClick()"/>
</div>

Step 2 : In the EmployeeComponent class ie. in employee.component.ts file make the following changes

Inclue the following Import statement to import Router service from '@angular/router'
import { Router } from '@angular/router';

Specify a dependency on the Router service using the EmployeeComponent class constructor. The angular injector will automatically inject an instance of the Router service when an instance of EmployeeComponent is created.
constructor(private _router: Router) {
}

Finally include, "onBackButtonClick()" method. Notice we are using the Router service navigate() method to navigate to "/employees" route. This route is already defined in the root module (app.module.ts) which redirects the user to EmployeeListComponent.

onBackButtonClick() :void {
    this._router.navigate(['/employees']);
}

Video Link


Promises in angular 2 example

Suggested Videos
Part 35 - Angular Injector | Text | Slides
Part 36 - Angular root injector | Text | Slides
Part 37 - Angular router navigate method | Text | Slides

In this video we will discuss using Promises instead of Observables in Angular.


In Angular we can use either Promises or Observables. By default the Angular Http service returns an Observable. To prove this, hover the mouse over the get() method of the Http service in employee.service.ts file. Notice from the intellisense, that it returns Observable<Response>


Promises in angular 2 example

We discussed Observables in Part 27 of Angular 2 tutorial. To use Promises instead of Observables we will have to first make a change to the service to return a Promise instead of an Observable.

In employee.service.ts file modify getEmployeeByCode() method as shown below. The changes are commented so they are self-explanatory

import { Injectable } from '@angular/core';
import { IEmployee } from './employee';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/Observable/throw';
// import toPromise operator
import 'rxjs/add/operator/toPromise';

@Injectable()
export class EmployeeService {

    constructor(private _http: Http) { }

    getEmployees(): Observable<IEmployee[]> {
        return this._http.get('http://localhost:24535/api/employees')
            .map((response: Response) => <IEmployee[]>response.json())
            .catch(this.handleError);
    }

    // Notice we changed the return type of the method to Promise<IEmployee>
    // from Observable<IEmployee>. We are using toPromise() operator to
    // return a Promise. When an exception is thrown handlePromiseError()
    // logs the error to the console and throws the exception again
    getEmployeeByCode(empCode: string): Promise<IEmployee> {
        return this._http.get("http://localhost:24535/api/employees/" + empCode)
            .map((response: Response) => <IEmployee>response.json())
            .toPromise()
            .catch(this.handlePromiseError);
    }

    // This method is introduced to handle exceptions
    handlePromiseError(error: Response) {
        console.error(error);
        throw (error);
    }

    handleError(error: Response) {
        console.error(error);
        return Observable.throw(error);
    }
}

Modify the code in employee.component.ts file as shown below. The code that we have changed is commented and is self-explanatory.

import { Component, OnInit } from '@angular/core';
import { IEmployee } from './employee';
import { EmployeeService } from './employee.service';
import { ActivatedRoute } from '@angular/router';
import { Router } from '@angular/router';

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html',
    styleUrls: ['app/employee/employee.component.css']
})
export class EmployeeComponent implements OnInit {
    employee: IEmployee;
    statusMessage: string = 'Loading data. Please wait...';

    constructor(private _employeeService: EmployeeService,
        private _activatedRoute: ActivatedRoute,
        private _router: Router) { }

    ngOnInit() {
        let empCode: string = this._activatedRoute.snapshot.params['code'];
        // The only change that we need to make here is use
        // then() method instead of subscribe() method
        this._employeeService.getEmployeeByCode(empCode)
            .then((employeeData) => {
                if (employeeData == null) {
                    this.statusMessage =
                        'Employee with the specified Employee Code does not exist';
                }
                else {
                    this.employee = employeeData;
                }
            },
            (error) => {
                this.statusMessage =
                    'Problem with the service. Please try again after sometime';
                console.error(error);
            });
    }

    onBackButtonClick(): void {
        this._router.navigate(['/employees']);
    }
}

With the above changes, we are now using a Promise instead of an Observable and the application works the same way as before.

There are several differences between Observables and Promises. We will discuss these differences in our next video.

Video Link


Angular promises vs observables

Suggested Videos
Part 36 - Angular root injector | Text | Slides
Part 37 - Angular router navigate method | Text | Slides
Part 38 - Promises in angular 2 example | Text | Slides

In this video we will discuss the differences between promises and observables. In Angular 2, to work with asynchronous data we can use either Promises or Observables. In our previous videos in this series, we discussed using both Observables and Promises. There are several differences between Promises and Observables. In this video let's discuss these differences.


As a quick summary the differences are shown in the table below
Promise Observable
Emits a single value Emits multiple values over a period of time
Not Lazy Lazy. An Observable is not called until we subscribe to the Observable
Cannot be cancelled Can be cancelled using the unsubscribe() method
Observable provides operators like map, forEach, filter, reduce, retry, retryWhen etc.


A Promise emits a single value where as an Observable emits multiple values over a period of time. You can think of an Observable like a stream which emits multiple items over a period of time and the same callback function is called for each item emitted. So with an Observable we can use the same API to handle asynchronous data whether that data is emitted as a single value or multiple values over a period of time.

A Promise is not lazy where as an Observable is Lazy. Let's prove this with an example. Consider this method getEmployeeByCode() in employee.service.ts. Notice this method returns an Observable.

getEmployeeByCode(empCode: string): Observable<IEmployee> {
    return this._http.get("http://localhost:31324/api/employees/" + empCode)
        .map((response: Response) => <IEmployee>response.json())
        .catch(this.handleError);
}

Here is the consumer code of the above service. In our example, this code is in employee.component.ts in ngOnInit() method. Notice we are subscribing to the Observable using the subscribe() method. An Observable is lazy because, it is not called and hence will not return any data until we subscribe using the subscribe() method. At the moment we are using the subscribe() method. So the service method should be called and we should receive data.

ngOnInit() {
    let empCode: string = this._activatedRoute.snapshot.params['code'];

    this._employeeService.getEmployeeByCode(empCode)
        .subscribe((employeeData) => {
            if (employeeData == null) {
                this.statusMessage =
                    'Employee with the specified Employee Code does not exist';
            }
            else {
                this.employee = employeeData;
            }
        },
        (error) => {
            this.statusMessage =
                'Problem with the service. Please try again after sometime';
            console.error(error);
        });
}

To prove this 
1. Launch Browser developer tools by pressing F12 while you are on the browser. 
2. Navigate to /src/employees/emp101
3. Click on the Network Tab
4. In the Filter textbox, type "api/employees"
5. At this point, you should only see the request issued to EmployeeService in the table below
6 Hover the mouse over "emp101" under "Name" column in the table
7. Notice the request to employee service (/api/employees/emp101) is issued

lazy observable

Instead of hovering over the request, if you click on it, you can see the response data as shown below. Make sure you select the "preview" tab.

lazy observablecollection

Now in employee.component.ts file, comment the subscribe() method code block as shown below. Notice we are still calling the getEmployeeByCode() method of the EmployeeService. Since we have not subscribed to the Observable, a call to the EmployeeService will not be issued over the network.

ngOnInit() {
    let empCode: string = this._activatedRoute.snapshot.params['code'];

    this._employeeService.getEmployeeByCode(empCode)
        //.subscribe((employeeData) => {
        //    if (employeeData == null) {
        //        this.statusMessage =
        //            'Employee with the specified Employee Code does not exist';
        //    }
        //    else {
        //        this.employee = employeeData;
        //    }
        //},
        //(error) => {
        //    this.statusMessage =
        //        'Problem with the service. Please try again after sometime';
        //    console.error(error);
        //});
}

With the above change in place, reload the web page. Notice no request is issued over the network to the EmployeeService. You can confirm this by looking at the network tab in the browser developer tools. So this proves that an Observable is lazy and won't be called unless we subscribe using the subscribe() method.

Now, let's prove that a Promise is NOT Lazy. I have modified the code in employee.service.ts to return a Promise instead of an Observable. The modified code is shown below.

getEmployeeByCode(empCode: string): Promise<IEmployee> {
    return this._http.get("http://localhost:31324/api/employees/" + empCode)
        .map((response: Response) => <IEmployee>response.json())
        .toPromise()
        .catch(this.handlePromiseError);
}

Here is the consumer code of the above service. In our example, this code is in employee.component.ts in ngOnInit() method. 

ngOnInit() {
    let empCode: string = this._activatedRoute.snapshot.params['code'];

    this._employeeService.getEmployeeByCode(empCode)
        .then((employeeData) => {
            if (employeeData == null) {
                this.statusMessage =
                    'Employee with the specified Employee Code does not exist';
            }
            else {
                this.employee = employeeData;
            }
        },
        (error) => {
            this.statusMessage =
                'Problem with the service. Please try again after sometime';
            console.error(error);
        });
}

Because a promise is eager(not lazy), calling employeeService.getEmployeeByCode(empCode) will immediately fire off a request across the network to the EmployeeService. We can confirm this by looking at the network tab in the browser tools. 

Now you may be thinking, then() method in this case is similar to subscribe() method. If we comment then() method code block, will the service still be called. The answer is YES. Since a Promise is NOT LAZY, Irrespective of whether you have then() method or not, calling employeeService.getEmployeeByCode(empCode) will immediately fire off a request across the network to the EmployeeService. You can prove this by commenting then() method code block and reissuing the request.

In our next video, we will discuss how to retry when a request fails and in the video after that we will discuss how cancel an Observable.

Video Link


Observable retry on error

Suggested Videos
Part 37 - Angular router navigate method | Text | Slides
Part 38 - Promises in angular 2 example | Text | Slides
Part 39 - Angular promises vs observables | Text | Slides

In this video we will how to resubscribe and retry an Observable if there is an error.



Please change getEmployeeByCode() method in employee.service.ts file to return an Observable instead of a Promise as shown below.

getEmployeeByCode(empCode: string): Observable<IEmployee> {
    return this._http.get("http://localhost:24535/api/employees/" + empCode)
        .map((response: Response) => <IEmployee>response.json())
        .catch(this.handleError);
}



To cause an error, stop the Web API Service. At this point if you navigate to http://localhost:12345/src/employees/emp101, the application display a message stating - Problem with the service. Please try again after sometime. In the "Console" tab of the "Browser Developer Tools" you will see - ERR_CONNECTION_REFUSED.
Observable retry on error

To resubscribe to the Observable and retry, use the rxjs retry operator. The changes in employee.component.ts file are commented and self explanatory.

import { Component, OnInit } from '@angular/core';
import { IEmployee } from './employee';
import { EmployeeService } from './employee.service';
import { ActivatedRoute } from '@angular/router';
import { Router } from '@angular/router';

// Import rxjs retry operator
import 'rxjs/add/operator/retry';


@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html',
    styleUrls: ['app/employee/employee.component.css']
})
export class EmployeeComponent implements OnInit {
    employee: IEmployee;
    statusMessage: string = 'Loading data. Please wait...';
    retryCount: number = 1;

    constructor(private _employeeService: EmployeeService,
        private _activatedRoute: ActivatedRoute,
        private _router: Router) { }

    ngOnInit() {
        let empCode: string = this._activatedRoute.snapshot.params['code'];

        this._employeeService.getEmployeeByCode(empCode)
            // Chain the retry operator to retry on error.
            .retry()
            .subscribe((employeeData) => {
                if (employeeData == null) {
                    this.statusMessage =
                        'Employee with the specified Employee Code does not exist';
                }
                else {
                    this.employee = employeeData;
                }
            },
            (error) => {
                this.statusMessage =
                    'Problem with the service. Please try again after sometime';
                console.error(error);
            });
    }

    onBackButtonClick(): void {
        this._router.navigate(['/employees']);
    }
}

The downside of this approach is that the application keeps on retrying forever. If we start the Web API service, the call succeeds and the observable completes with employee data displayed on the web page.

Now if your requirement is not to retry forever, but only retry for a specific number of times if there is an error then we can use another variation of retry as shown below. Notice in this case we are passing number 3 to the retry opertaor indicating that we only want to retry 3 times. After the 3rd attempt the observable completes with an error.

ngOnInit() {
    let empCode: string = this._activatedRoute.snapshot.params['code'];

    this._employeeService.getEmployeeByCode(empCode)
        // Retry only 3 times if there is an error
        .retry(3)
        .subscribe((employeeData) => {
            if (employeeData == null) {
                this.statusMessage =
                    'Employee with the specified Employee Code does not exist';
            }
            else {
                this.employee = employeeData;
            }
        },
        (error) => {
            this.statusMessage =
                'Problem with the service. Please try again after sometime';
            console.error(error);
        });
}

The problem with the retry operator is that, it immidiately retries when there is an error. In our case it is a connection issue with the service. Retrying again immediately in our case does not make much sense, as most likely it might fail again. So in situations like this we may want to retry after a short delay, may be after a second or so. This is when we use the retryWhen rxjs operator. retryWhen operator allows us to specify delay in milli-seconds and can be used as shown below. Please donot forget to import retryWhen and delay operators.

import 'rxjs/add/operator/retrywhen';
import 'rxjs/add/operator/delay';

ngOnInit() {
    let empCode: string = this._activatedRoute.snapshot.params['code'];

    this._employeeService.getEmployeeByCode(empCode)
        // Retry with a delay of 1000 milliseconds (i.e 1 second)
        .retryWhen((err) => err.delay(1000))
        .subscribe((employeeData) => {
            if (employeeData == null) {
                this.statusMessage =
                    'Employee with the specified Employee Code does not exist';
            }
            else {
                this.employee = employeeData;
            }
        },
        (error) => {
            this.statusMessage =
                'Problem with the service. Please try again after sometime';
            console.error(error);
        });
}

Now if you are wondering can't we use delay opertor with retry operator, the answer is NO, we can't. The delay operator in the following example will not work as expected. As you can see from the browser console, it immediately retries instead of waiting for 5 seconds before a retry attempt.

ngOnInit() {
    let empCode: string = this._activatedRoute.snapshot.params['code'];

    this._employeeService.getEmployeeByCode(empCode)
        // The delay operator will not work with retry
        .retry().delay(5000)
        .subscribe((employeeData) => {
            if (employeeData == null) {
                this.statusMessage =
                    'Employee with the specified Employee Code does not exist';
            }
            else {
                this.employee = employeeData;
            }
        },
        (error) => {
            this.statusMessage =
                'Problem with the service. Please try again after sometime';
            console.error(error);
        });
}

If you want to retry every 1000 milli-seconds only for a miximum of 5 times then we can use rxjs scan operator along with the take operator. While retrying we also want to show the retry attempt number to the user on the web page as shown below.
observable retry example

After all the retry attempts are exhausted, the application should stop retrying and display the error message to the user as shown below.
observable retry with delay

If the connection becomes available between the retry attempts, the application should display employee data.

Here is the complete code.

import { Component, OnInit } from '@angular/core';
import { IEmployee } from './employee';
import { EmployeeService } from './employee.service';
import { ActivatedRoute } from '@angular/router';
import { Router } from '@angular/router';

import 'rxjs/add/operator/retrywhen';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/scan';

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html',
    styleUrls: ['app/employee/employee.component.css']
})
export class EmployeeComponent implements OnInit {
    employee: IEmployee;
    statusMessage: string = 'Loading data. Please wait...';
    retryCount: number = 1;

    constructor(private _employeeService: EmployeeService,
        private _activatedRoute: ActivatedRoute,
        private _router: Router) { }

    ngOnInit() {
        let empCode: string = this._activatedRoute.snapshot.params['code'];

        this._employeeService.getEmployeeByCode(empCode)
            // Retry 5 times maximum with a delay of 1 second
            // between each retry attempt
            .retryWhen((err) => {
                return err.scan((retryCount, val) => {
                    retryCount += 1;
                    if (retryCount < 6) {
                        this.statusMessage = 'Retrying...Attempt #' + retryCount;
                        return retryCount;
                    }
                    else {
                        throw (err);
                    }
                }, 0).delay(1000)
            })
            .subscribe((employeeData) => {
                if (employeeData == null) {
                    this.statusMessage =
                        'Employee with the specified Employee Code does not exist';
                }
                else {
                    this.employee = employeeData;
                }
            },
            (error) => {
                this.statusMessage =
                    'Problem with the service. Please try again after sometime';
                console.error(error);
            });
    }

    onBackButtonClick(): void {
        this._router.navigate(['/employees']);
    }
}

In our next video, we will discuss how to allow the end user to cancel retry attempts at any point using the unsubscribe method.

Video Link


Angular observable unsubscribe

Suggested Videos
Part 38 - Promises in angular 2 example | Text | Slides
Part 39 - Angular promises vs observables | Text | Slides
Part 40 - Observable retry on error | Text | Slides

In this video, we will discuss how to cancel an Observable using the unsubscribe method. This is continuation to Part 40, please watch Part 40 from Angular 2 tutorial before proceeding.


Let us understand this with an example. Here is what we want to do. When the request to the server is in progress we want to display "Cancel Request" button.
Angular observable unsubscribe


The "Cancel Request" button should only be visible to the user when there is a request in progress. When the request fails permanently after exhausting all the retry attempts the button should disappear. 
observable unsubscribe example

Along the same lines if the request completes successfully, then also the button should disappear.
how to unsubscribe from observable angular 2

When the user cancels the request, by clicking the "Cancel Request" button, the request should be cancelled and button should disappear.
angular cancel observable

To achieve this, include the following HTML in employee.component.html file. This HTML is for the "Cancel Request" button. Please pay attention to the structural directive ngIf on the <div> element that contains the button. As you can see we are showing the "Cancel Request" button only if the subscription is not closed (!subscription.closed), meaning only when there is a request to the Observable is in progress. 

The ngIf directive will take care of showing and hiding the <div> element depending on whether the subscription is closed or not. We are also binding the click event of the button to "onCancelButtonClick()" method. We will create both the subscription object and the "onCancelButtonClick()" method in the component class.

<div style="margin-top:5px" *ngIf="!subscription.closed">
    <input type="button" class="btn btn-primary" value="Cancel Request"
           (click)="onCancelButtonClick()" />
</div>

Now modify the code in employee.component.ts file as shown below. The relavant code is commented and self-explanatory.

import { Component, OnInit } from '@angular/core';
import { IEmployee } from './employee';
import { EmployeeService } from './employee.service';
import { ActivatedRoute } from '@angular/router';
import { Router } from '@angular/router';

import 'rxjs/add/operator/retrywhen';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/scan';
// import ISubscription.
import { ISubscription } from "rxjs/Subscription";

@Component({
    selector: 'my-employee',
    templateUrl: 'app/employee/employee.component.html',
    styleUrls: ['app/employee/employee.component.css']
})
export class EmployeeComponent implements OnInit {
    employee: IEmployee;
    statusMessage: string = 'Loading data. Please wait...';
    retryCount: number = 1;

    // Create a class property of type ISubscription
    // The ISubscription interface has closed property
    // The ngIf directive in the HTML binds to this property
    // Go to the difinition of ISubscription interface to
    // see the closed property
    subscription: ISubscription;

    constructor(private _employeeService: EmployeeService,
        private _activatedRoute: ActivatedRoute,
        private _router: Router) { }

    ngOnInit() {
        let empCode: string = this._activatedRoute.snapshot.params['code'];

        // Use the subscription property created above to hold on to the
        // subscription.We use this object in the onCancelButtonClick()
        // method to unsubscribe and cancel the request
        this.subscription = this._employeeService.getEmployeeByCode(empCode)
            .retryWhen((err) => {
                return err.scan((retryCount, val) => {
                    retryCount += 1;
                    if (retryCount < 4) {
                        this.statusMessage = 'Retrying...Attempt #' + retryCount;
                        return retryCount;
                    }
                    else {
                        throw (err);
                    }
                }, 0).delay(1000)
            })
            .subscribe((employeeData) => {
                if (employeeData == null) {
                    this.statusMessage =
                        'Employee with the specified Employee Code does not exist';
                }
                else {
                    this.employee = employeeData;
                }
            },
            (error) => {
                this.statusMessage =
                    'Problem with the service. Please try again after sometime';
                console.error(error);
            });
    }

    onBackButtonClick(): void {
        this._router.navigate(['/employees']);
    }

    // This method is bound to the click event of the "Cancel Request" button
    // Notice we are using the unsubscribe() method of the subscription object
    // to unsubscribe from the observable to cancel the request. We are also
    // setting the status message property of the class to "Request Cancelled"
    // This message is displayed to the user to indicate that the request is cancelled
    onCancelButtonClick(): void {
        this.statusMessage = 'Request cancelled';
        this.subscription.unsubscribe();
    }
}

Video Link


Difference between AngularJS, Angular 2 and Angular 4

Suggested Videos
Part 39 - Angular promises vs observables | Text | Slides
Part 40 - Observable retry on error | Text | Slides
Part 41 - Angular observable unsubscribe | Text | Slides

So far Google  has released 3 versions of Angular and you can see the timelines below.
Version Year
AngularJS 2010
Angular 2 2016
Angular 4 2017


In this video, let's discuss the differences between these versions. 


What is the difference between AngularJS and Angular 2
The first version of Angular is called AngularJS and was released in the year 2010. Some people call it Angular 1, but it is officially called AngularJS. 

Angular 2 is released in the year 2016. The most important thing to keep in mind is that, Angular 2 is not a simple upgrade from angular 1. 

Angular 2 is completely rewritten from the ground up and as a result the way we write applications with AngularJS and Angular 2 is very different. 

AngularJS applications revolve around the concept of controllers. To glue a controller and a view in AngularJS we use $scope. With Angular 2 both controllers and $scope are gone. Angular 2 is entirely component based, which means we create a set of independent or loosely coupled components and put them together to create an Angular 2 application. So components are the building blocks of an Angular 2 application. The advantage of the component-based approach is that, it facilitates greater code reuse. For example, if you have a rating component, you may use it on an employee page to rate an employee or on a product page to rate a product. From unit testing standpoint, the use of components make Angular2 more testable. 

From a performance standpoint, Angular 2 is 5 times faster compared to AngularJS.

AngularJS was not built for mobile devices, where as Angular 2 on the other hand is designed from the ground up with mobile support in mind. 

With Angular 2 we have more language choices. In additon to nativa JavaScript we can use TypeScript, Dart, PureScript, Elm, etc. Among all these languages, TypeScript is the most popular language for developing Angular 2 applications as it provides the following benefits.
1. Intellisense 
2. Autocompletion
3. Code navigation
4. Advanced refactoring
5. Strong Typing
6. Supports ES 2015 (also called ES 6) features like classes, interfaces and inheritance. 

We already discussed these differences in Part 1 of Angular 2 tutorial

Angular 4 is released in 2017. So, What is the difference between Angular 2 and Angular 4

If you have worked with both Angular 1 and Angular 2, then you already know that the API's and patterns that we use to build applications are very different between these 2 versions. From a developer stand point, it is like learning 2 different frameworks. Since Angular 2 is a complete rewrite from Angular 1, moving from Angular 1 to Angular 2 is a total breaking change. 

However, changing from Angular 2 to Angular 4 and even future versions of Angular, won’t be like changing from Angular 1. It won’t be a complete rewrite, it will simply be a change in some core libraries. From a developer standpoint, building an application using Angular 2 and Angular 4 is not very different. We still use the same concepts and patterns.  Angular 4 is simply, the next version of Angular 2. The underlying concepts are still the same and if you have already learnt Angular 2 then you’re well prepared to switch to Angular 4.

The most important point to keep in mind is, Angular 4 is backwards compatible with Angular 2 for most applications.

What has changed and what is new in Angular 4

Some under the hood changes to reduce the size of the AOT (Ahead-of-Time) compiler generated code. Migrating to Angular 4 may reduce the production bundles by hundreds of kilobytes. As a developer this change will not affect the way we write angular applications in any way.

TypeScript 2.1 and 2.2 compatibility. Angular is updated with a more recent version of TypeScript, for better type checking throughout our application. Up until Angular 4, only TypeScript 1.8 was supported. With Angular 4, we can use typescript 2.1 or 2.2 which means we can use all the new features of TypeScript with Angular 4.

Animation features are pulled out of @angular/core and are moved into their own package. This means that if you don’t use animations, this extra code will not end up in your production bundles. On the other hand, if you do have animations in your application, you may have to change your existing code to pull the animation features from the animations package.

We can now use an if/else style syntax with *ngIf structural directive. In Angular 2, to implement if/else logic, we use 2 *ngIf structural directives. With Angular 4, we can use it's new if/else style syntax with *ngIf structural directive. We will discuss an example of this in our upcoming videos.

What happened to Angular 3. Why did we move straight from Angular 2 to Angular 4. What is the reason for skipping Angular 3.
Except the Router library, all the other Angular core libraries are versioned the same way and are shipped as NPM packages as you can see below. While all the other core angular packages are at Version 2, the router library is already at Version 3.
why angular 3 is not released

Due to this misalignment of the router package’s version, the angular team decided to go straight for Angular v4. This way, all the core packages are aligned which will be easier to maintain and help avoid confusion in the future.

Some naming guidelines are also provided by the Angular team
  1. Use "AngularJS" to describe versions 1.x or earlier
  2. Use "Angular" for versions 2.0.0 and later. 
  3. Use the version numbers "Angular 4.0", "Angular 2.4" when you need to talk about a specific release. Otherwise it is just enough if you use the word Angular. For example, you are an Angular developer and not Angular 2.0 developer or Angular 4.0 developer.
  4. Angular 4 is simply, the next version of Angular 2. The underlying concepts are still the same and if you have already learnt Angular 2 then you’re well prepared to switch to Angular 4.
Do I have to learn AngularJS 1 before learning Angular 2
No. You can think of AngularJS 1 and Angular 2 as 2 different frameworks. The concepts, the API's and patterns that we use to build applications are very different between these 2 versions. So there is no need to learn AngularJS 1 before you learn Angular 2.

Do I have to learn Angular 2 before learning Angular 4
From a developer standpoint, building an application using Angular 2 and Angular 4 is not very different. We still use the same concepts, APIs and patterns. Angular 4 is simply, the next version of Angular 2 and contains a few changes and enhancements as discussed above. So you really have 2 options here. Learn Angular 2 first and then the changes and enhancements introduced in Angular 4, OR learn all the angular concepts using version 4. Either ways you are an Angular developer. 

Video Link


Angular 2 course wrap up and what's next

Suggested Videos
Part 40 - Observable retry on error | Text | Slides
Part 41 - Angular observable unsubscribe | Text | Slides
Part 42 - Difference between AngularJS, Angular 2 and Angular 4 | Text | Slides

In this video we will wrap up Angular 2 course and also get an idea of what we plan to do next.


So far in this Angular 2 course we discussed all the basics of Angular 2 framework. We have discussed
  • What is a component
  • Creating a component and a nested component
  • Passing data between parent and child components using component input and output properties
  • Different ways of applying styles to components
  • We also discussed interpolation, property, class, style and event bindings
  • How angular two way data binding keeps component class properties and HTML element values in sync
  • Using angular structural directives ngIf and ngFor
  • Transform data before display using built-in angular pipes and creating our own custom pipes
  • How to create custom types for the business objects that we create in a real-world application like Employee, Customer, Order, etc using the TypeScript interfaces
  • Component Life Cycle Hooks
  • Creating a service that retrieves data from a remote web service
  • Using Bootstrap to style Angular components
  • How routing works in angular and passing parameters to routes
  • What is Dependency Injection and how it is implemented in Angular
  • How to work with Observables and Promises in Angular

As you have seen throughout the course, Angular provides consistent set of patterns for creating components, pipes and services. As we already discussed in our previous video, from a developer standpoint, there is no much difference between Angular 2 and Angular 4. The way we create an angular application is very identical whether we use Angular 2 or Angular 4 version. Angular 4 is simply the next version of Angular 2. All the angular concepts that we have learnt so far as part of this course are still valid, and we can still use those same concepts to build angular applications using Angular version 4.

So here is what we plan to do next
A short course on a tool called Angular CLI. Angular CLI is a command line tool, that help us create, build and test angular applications faster and with great consistency while following angular conventions and  best practices. This tool generates the boiler plate code in no time for components, directives, pipes, services etc. I personally think Angular CLI is an extremely useful tool and every angular developer should know how to use it as it greatly improves our productivity when developing angular application. As part of this short course on Angular CLI, we will learn everything we need to know to effectively and efficiently use this tool to improve our productivity while still following angular best practices and conventions.

So, once we are comfortable with this Angular CLI tool. We will use it to create a brand new Angular 4 project from scratch. As part of this project we will learn 
How to perform CRUD (i.e Create, Read, Update & Delete) operations in Angular. To learn all these CRUD operations we will create a form that looks as shown below. Along the way we also discuss form validation and working with different HTML elements like textboxes, radio buttons, checkboxes, select list etc. We will also discuss using third party form controls like Datepicker, Rating control etc.
angular 2 crash course

If you have a comment, question or would like us to include any other angular concept in our upcoming courses, please leave them as comments on this video and we will surely include them.

So please stay tuned for our upcoming new angular courses.

Video Link
Suggested Video Tutorials
Angular CLI
Angular 2
Bootstrap




Block-2



Setting up a new angular project from scratch is a tedious and time consuming process. However, Angular CLI makes it super fast and easy. With angular development, we write same boiler plate code to create components, pipes, services, directives etc. Manually creating these consumes lot of time. Angular CLI can generate these with lightning speed while still following Angular's best practices and conventions. So basic knowledge of Angular CLI is very helpful.


The prerequisites for this course are basic knowledge of Bootstrap, Angular CLI and Angular 2. If you are new to these please check out our courses using the links below.
  1. Angular CLI
  2. Angular 2
  3. Bootstrap
Installing the tools required

Node : Install the latest version of node. Here is the link to download and install the latest version
https://nodejs.org/en/download/

As of this recording the latest version is 8.9.2 which is what I have installed. Run windows command prompt as an administrator and execute the following command to verify the version of node installed on your machine.
node -v

Angular CLI : Install the latest version of Angular CLI by executing the following command from the windows command prompt. 
npm install -g @angular/cli

As of this recording, the latest version is 1.6.0 which is what I have installed on my machine. To verify the version of Angular CLI installed on your machine execute the following command.
ng -v

Another question that you might have is, which version of Angular are we using with this course. As of this recording, the latest version is Angular 5, which is what we will be using. 

After you have the latest version of Node and Angular CLI installed, launch windows command prompt as an administrator and execute the following command. This creates a new AngularProject with name AngularCrud. We do not want test files to be generated for the root component AppComponent, so we have set "skip-tests" option to true. We will discuss unit testing components in a later video.
ng new AngularCrud --skip-tests true

This command creates a brand new Angular Project with name AngularCrud. In windows command prompt change to the directory that contains your angular project using the following command.
cd AngularCrud

Once you are in the project directory, execute the following command to open the project with Visual Studio Code, by executing the following command from the windows command prompt 
code .

Once you have the Angular project opened in Visual Studio Code, open package.json file and notice that we are using Angular 5.
how to check angular project version

We will be using Bootstrap for styles in our application. So install Bootstrap by executing the following command from the command prompt.
npm install bootstrap@3 --save

Once Bootstrap is installed, open .angular-cli.json file and specify the path to the Bootstrap stylesheet (bootstrap.min.css) in the styles property as shown below.

"styles": [
  "../node_modules/bootstrap/dist/css/bootstrap.min.css",
  "styles.css"

]

Video Link

Part 2



Reading data in angular

Suggested Videos
Part 1 - Angular project setup | Text | Slides

In this video we will discuss performing the READ operation in Angular. In our upcoming videos, we will discuss the rest of the CRUD operations i.e Creating, Updating and Deleting.


Let us understand implementing the READ operation with an example. We want to display list of employees as shown below.
angular list component


At the moment, we do not have Employee model. First, let's create the Employee model. 

Creating Employee model : 
  1. In Visual Studio Code, expand the "src" folder
  2. Right click on the "App" folder, and select "New Folder" from the context menu
  3. Name the folder "models". We will place all our models in this folder
  4. Now add a new file in the "models" folder
  5. Name it "employee.model.ts"
  6. Copy and paste the following code in it
export class Employee {
    id: number;
    name: string;
    gender: string;
    email?: string;
    phoneNumber?: number;
    contactPreference: string;
    dateOfBirth: Date;
    department: string;
    isActive: boolean;
    photoPath?: string;
}

Next, create a component to display the list of employees. Name it ListEmployeesComponent.

Creating ListEmployeesComponent : Use the following AngularCLI command to create ListEmployeesComponent. We will place all employee CRUD components in "employees" folder. This is the reason we prefixed the "employees" folder name in the command. Also, notice we have set --flat option to true as we do not want to place the ListEmployeesComponent files in it's own dedicated folder.

ng g c employees/listEmployees --spec false --flat true

The above command not only creates the ListEmployeesComponent, it also updates the AppModule. In the app.module.ts file it has imported ListEmployeesComponent and included it in the declarations array. So the Angular CLI has generated lot of boiler plate code, that we would have to write manually otherwise.

Creating images folder : We will place all the images that we are going to use in "images" folder. We will have the images folder in the "assets" folder. So add a new folder in the "assets" folder and name it "images" and copy the following 3 images. Name the images mark.png, mary.png and john.png.







Changes in list-employees.component.ts : The changes are commented and self-explanatory

import { Component, OnInit } from '@angular/core';
// import Employee Model
import { Employee } from '../models/employee.model';

@Component({
  selector: 'app-list-employees',
  templateUrl: './list-employees.component.html',
  styleUrls: ['./list-employees.component.css']
})
export class ListEmployeesComponent implements OnInit {
  // Hard code the employee data. In a later video we will discuss
  // how to retrieve this employees data from a database table
  employees: Employee[] = [
    {
      id: 1,
      name: 'Mark',
      gender: 'Male',
      contactPreference: 'Email',
      email: 'mark@pragimtech.com',
      dateOfBirth: new Date('10/25/1988'),
      department: 'IT',
      isActive: true,
      photoPath: 'assets/images/mark.png'
    },
    {
      id: 2,
      name: 'Mary',
      gender: 'Female',
      contactPreference: 'Phone',
      phoneNumber: 2345978640,
      dateOfBirth: new Date('11/20/1979'),
      department: 'HR',
      isActive: true,
      photoPath: 'assets/images/mary.png'
    },
    {
      id: 3,
      name: 'John',
      gender: 'Male',
      contactPreference: 'Phone',
      phoneNumber: 5432978640,
      dateOfBirth: new Date('3/25/1976'),
      department: 'IT',
      isActive: false,
      photoPath: 'assets/images/john.png'
    },
  ];
  constructor() { }

  ngOnInit() {
  }
}

Changes in list-employees.component.html : Replace the existing HTML, with the following HTML. Notice we are using Bootstrap for styling.

<div class="panel panel-primary" *ngFor="let employee of employees">
  <div class="panel-heading">
    <h3 class="panel-title">{{employee.name}}</h3>
  </div>
  <div class="panel-body">

    <div class="col-xs-10">

      <div class="row vertical-align">

        <div class="col-xs-4">
          <img class="imageClass" [src]="employee.photoPath" />
        </div>
        <div class="col-xs-8">

          <div class="row">
            <div class="col-xs-6">
              Gender
            </div>
            <div class="col-xs-6">
              : {{employee.gender}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Date of Birth
            </div>
            <div class="col-xs-6">
              : {{employee.dateOfBirth | date}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Contact Preference
            </div>
            <div class="col-xs-6">
              : {{employee.contactPreference}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Phone
            </div>
            <div class="col-xs-6">
              : {{employee.phoneNumber}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Email
            </div>
            <div class="col-xs-6">
              : {{employee.email}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Department
            </div>
            <div class="col-xs-6">
              : {{employee.department}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Is Active
            </div>
            <div class="col-xs-6">
              : {{employee.isActive}}
            </div>
          </div>

        </div>

      </div>
    </div>
  </div>
</div>

Changes in list-employees.component.css : Include the following CSS classes

.imageClass{
    width:200px;
    height:200px;
}
.vertical-align{
    display: flex;
    align-items: center;
}

Changes in app.component.html : Include the ListEmployeesComponent selector (app-list-employees) as a directive in the root component (app.component.html)
<div class="container">
    <app-list-employees></app-list-employees>
</div>

At this point, save all the changes and run the angular project using the following command. This command not only compiles the angular application, it also launches your default browser and displays the list of employees as expected.
ng serve -o

We have just seen how to perform the READ operation. In our next video, we will set up routing.

Suggested Videos
Part 1 - Angular project setup | Text | Slides
Part 2 - Reading data in angular | Text | Slides

In this video we will discuss setting up routing in our sample application. Here are the steps.


Step 1 : At the moment, in our application we have only one component (ListEmployeesComponent). Let's create another component. In our upcoming videos we will discuss how to create a new employee. So let's add CreateEmployeeComponent. Use the following Angular CLI command to generate the component.

ng g c employees/createEmployee --spec false --flat true


Step 2 : Set <base href="/"> in the application host page which is index.html. The <base href> tells the angular router how to compose navigation URLs. This is already done for us by the Angular CLI, when we created this project.

<base href="/">

We will discuss the significance of this base href element in detail in our next video.

Step 3 : Import the RouterModule into the application root module AppModule. The Router Module contains the Router service and Router directives such as (RouterLink, RouterLinkActive, RouterOutlet etc). So for us to be able to implement routing, we first need to import the Router Module in our AppModule. So in app.module.ts make the following changes. Notice the changes are commented and self-explanatory.

// Import RouterModule
import { RouterModule } from '@angular/router';

// Include RouterModule in the "imports" array of the @NgModule() decorator
@NgModule({
  declarations: [...
  ],
  imports: [
    BrowserModule,
    RouterModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})

export class AppModule { }

Step 4 : Configure the application routes. 

To configure routes, we first need to import Routes type from '@angular/router'. If you look at the definition of Routes type, it is actually an array of Route objects. This Routes type is not required for the application to work. However, using it provides us intellisense and compile time checking. For example, mis-spelled properties of the Route object will be reported as errors.

import { RouterModule, Routes } from '@angular/router';

// Each route maps a URL path to a component
// The 3rd route specifies the route to redirect to if the path
// is empty. In our case we are redirecting to /list

// pathMatch property value can be full or prefix. For now we
// will set it to full as we want to do a full match. In our upcoming videos,
// we will discuss the difference between prefix and full in detail.

const appRoutes: Routes = [
  { path: 'list', component: ListEmployeesComponent },
  { path: 'create', component: CreateEmployeeComponent },
  { path: '', redirectTo: '/list', pathMatch: 'full' }
];

// To let the router know about the routes configured above,
// pass "appRoutes" constant to forRoot(appRoutes) method
// We also have forChild() method. We will discuss the difference
// and when to use one over the other in our upcoming videos

@NgModule({
declarations: [...
],
imports: [
  BrowserModule,
  RouterModule.forRoot(appRoutes)
],
providers: [],
bootstrap: [AppComponent]
})

export class AppModule { }

Step 5 : Create the application menu and tie the routes to it. Notice we are using routerLink directive. This directive tells the router where to navigate when the user clicks the link. We are also using router-outlet directive. This directive specifies where you want the routed component view template to be displayed. We want our navigation menu to be always displayed, so the ideal location for it is the root component AppComponent i.e app.component.html file. When the application first loads, it loads the root AppComponent in index.html. So let's place the following HTML in app.component.html file.

<div class="container">
    <nav class="navbar navbar-default">
        <ul class="nav navbar-nav">
            <li>
                <a routerLink="list">List</a>
            </li>
            <li>
                <a routerLink="create">Create</a>
            </li>
        </ul>
    </nav>
    <router-outlet></router-outlet>
</div>

As you can see, in the HTML we have 2 things - Navigation menu and the <router-outlet> directive. The navigation menu is always displayed. Below the navigation menu, we have the <router-outlet> directive. This is the location where the routed component view template is displayed. 

For example, when we click on the "List" link in the navigation menu, the route changes to "/list" and the ListEmployeesComponent view template is displayed at the location where we have the <router-outlet> directive. At this point, if we click on "Create" link, 2 things happen

1. The route changes from "/list" to "/create" 
2. ListEmployeesComponent view template is replaced with CreateEmployeeComponent view template

Also notice, if we navigate to the root of the application i.e if we do not include "/list" or "/create" in the URL, the router automatically redirects us to "/list". This is because of the following empty route we have in our route configuration.

{ path: '', redirectTo: '/list', pathMatch: 'full' }

We are using Bootstrap navbar component to create the navigation menu. We discussed Bootstrap navbar component in Part 28 of Bootstrap tutorial.

Since we are now routing to ListEmployeesComponent we no longer need it's selector. So remove the selector specified in the @Component decorator of ListEmployeesComponent

At the moment both the menu items, i.e the active and the inactive menu items are styled the same way. As a result we don't know which page the user is on. We will discuss how to address this in our upcoming videos.

In our next video, we will discuss the significance of the <base href="/"> element in index.html page.

vid link
Suggested Videos
Part 1 - Angular project setup | Text | Slides
Part 2 - Reading data in angular | Text | Slides
Part 3 - Angular routing and navigation | Text | Slides

In this short video we will discuss the significance of the base href element in Angular.


When setting up routing in an angular application, the first step is to set the base path using the base href element. The base path tells the angular router, how to compose the navigation URLs. The browser uses the <base href> value to prefix relative URLs when referencing CSS files, scripts, and images.


During development we usually set this to a single forward slash as shown below. 
<base href="/">

This means all the URLs now will be relative to the root of the application. So when we navaigate to "/list", the path "/list" will be appended to root UR and the complete URL will be as shown below. Notice "/list" is relative to the root URL.
http://localhost:4200/list

Along the same lines, when we navigate to "/create", the complete URL is http://localhost:4200/create

When we deploy our application to a server, we typically deploy it to a sub folder on the server. For example, if we are deploying our application in a sub-folder called "emp", then we set the base href element to /emp/ as shown below.
<base href="/emp/">

This means all the URLs now will be relative to the "emp" base path and will be as shown below.
http://serverName/emp/list
http://serverName/emp/create

During development we usually set base href element to a single forward slash as shown below. 
<base href="/">

At this point, if we execute the following command, all the URLs will be relative to the root URL "http://localhost:4200"
ng serve -o 

Also, on the "sources" tab in the browser developer tools, you will find all the Script,  Images and Template files are relative to the root URL "http://localhost:4200" as shown in the image below.
angular base href

During development, if you want a different base path other than "/", simply execute the "ng serve" command with --base-href option set to your desired base path as shown below.
ng serve -o --base-href /emp/

At this point all the URLs will be relative to "http://localhost:4200/emp" as we have set the --base-href to /emp/. You can confirm this by looking at the URLs in the address bar and the "Sources" tab in the browser developer tools.
angular base href not working

On your local development machine, if you set the base href element in index.html to "/emp/" instead of a single "/" and if you run ng serve -o command without the "base-href" option  you will not see anything on the browser. When you open the browser developer tools, you will see the JavaScript bundle files failed to load. To fix this execute ng serve command along with the base href option as shown below.
ng serve -o --base-href /emp/

On your local development machine, if you set the base href element in index.html to a single forward slash and if you want to deploy your application on a server on sub-folder called "emp", then you will have to remember to update the base href element value in index.html to "/emp/". There are 2 ways we can do this.
  1. Manually update the index.html file OR
  2. Use the --base-href option along with the ng build command as shown below. This will update the "base href" element value index.html.ng build --base-href /emp/
vid link
Suggested Videos
Part 2 - Reading data in angular | Text | Slides
Part 3 - Angular routing and navigation | Text | Slides
Part 4 - Angular base href | Text | Slides

we discussed performing the READ operation. In this video and in the next few videos we will discuss performing the CREATE operation. To understand the CREATE operation, let us build a form that help us create a new employee. For this we will use the createEmployee component that we already created in one of our previous videos in this series. Along the way, we will also discuss performing validation and displaying meaningful error messages to the user.


There are 2 ways to create forms in Angular
  1. Template Driven Forms 
  2. Model Driven Forms (Commonly called Reactive Forms)

Both these approaches have their own pros and cons. For example, Template Driven forms are generally used to create simple forms. On the other hand, Reactive forms are used to create complex forms. For example, if you want to add form controls dynamically or perform cross-field validation we use the Reactive forms approach. There are several other differences, between Template driven and Reactive forms. We will discuss those differences in detail, in a later video.

In this video, we will use the Template driven approach to build the "Create Employee" form. As the name implies, template driven forms are heavy on the template. This means we do most of the work in the view template of the component. 

We want to design our "Create Employee" form as shown below. To keep this simple, at the moment we only have 2 fields (Full Name & Email). We will add the other fields like Gender, Department, Phone Number etc.. later. Also, at the moment, we only have textboxes on our form. In our upcoming videos we will discuss working with radio buttons, checkbox, dropdownlist etc
angular forms tutorial

Replace the HTML in "create-employee.component.html" file with the following HTML

<form #employeeForm="ngForm" (ngSubmit)="saveEmployee(employeeForm)">
  <div class="panel panel-primary">
    <div class="panel-heading">
      <h3 class="panel-title">Create Employee</h3>
    </div>
    <div class="panel-body">

      <div class="form-group">
        <label for="fullName">Full Name</label>
        <input id="fullName" type="text" class="form-control"
               name="fullName" [(ngModel)]="fullName">
      </div>

      <div class="form-group">
        <label for="email">Email</label>
        <input id="email" type="text" class="form-control"
               name="email" [(ngModel)]="email">
      </div>

    </div>
    <div class="panel-footer">
      <button class="btn btn-primary" type="submit">Save</button>
    </div>
  </div>
</form>

Angular Generated Form Model : {{employeeForm.value | json}}

Code Explanation: 
We are using Bootstrap CSS classes like panel, panel-primary, panel-heading, panel-title etc to style the form. There is no Angular here. If you are new to bootstrap, please click here to check out our Bootstrap tutorial.

Consider the following line of code
<form #employeeForm="ngForm" (ngSubmit)="saveEmployee(employeeForm)">

#employeeForm is called the template reference variable. Notice we have assigned "ngForm" as the value for the template reference variable employeeForm. So employeeForm variable holds a reference to the form. When Angular sees a form tag, it automatically attaches the ngForm directive to it. The ngForm directive supplements the form element with additional features. It holds all the form controls that we create with ngModel directive and name attribute, and monitors their properties like value, dirty, touched, valid etc. The form also has all these properties. We will discuss these properties at the individual control level and at the form level in detail in our upcoming videos.

The ngSubmit directive submits the form when we hit the enter key or when we click the Submit button. When the form is submitted, saveEmployee() method is called and we are passing it the employeeForm. We do not have this method yet. We will create it in the component class in just a bit.

The ngForm directive is provided by Angular FormsModule. So for us to be able to use it, we will have to import the FormsModule in our AppModule file (app.module.ts). So please make sure to include the following import statement. Also include "FormsModule" in the imports array of @NgModule decorator.
import { FormsModule } from '@angular/forms';

If "FormsModule" is not imported you will see the following error in the browser developer toolsthere is no directive with exportas set to ngform

Consider the following block of code

<div class="form-group">
  <label for="fullName">Full Name</label>
  <input id="fullName" type="text" class="form-control"
          name="fullName" [(ngModel)]="fullName">
</div>
  1. To style the "Full Name" field and it's associated label, we are using Bootstrap. So "form-group" and "form-control" are Bootstrap CSS classes used for styling. There is no Angular here.
  2. The "for" attribute on the label, is used to link the label with it's associated "fullName" input control. With the "for" attribute in place, when we click on the label, it's associated input element automatically receives the focus. Again there is no Angular here. It's all standard HTML.
  3. The ngModel directive is used for creating two-way data binding i.e to keep the HTML element value and it's corresponding component property in sync. We discussed two-way data binding in detail in our Angular 2 course. Click here to watch two-way data binding video.
  4. Notice we have set ngModel directive to "fullName". We do not have "fullName" property in the component class. Angular automatically creates "fullName" property using the value of the "name" attribute of the HTML input element. This is why "name" attribute is also required when we use ngModel directive. If we remove the "name" attribute, we get the following error.
    If ngModel is used within a form tag, either the name attribute must be set or the form control must be defined as 'standalone' in ngModelOptions
  5. So the bottom line is, if you want an input element to be tracked by the form make sure to include both the name attribute and ngModel directive. Otherwise that input element will not be part of the Form model created by Angular.
Consider the following piece of code : We are using the value property of the employeeForm to display fullName and email property values of the Form Model that angular automatically generates for us. We are using the Angular "json" pipe to format the JSON data.

Angular Generated Forom Model : {{employeeForm.value | json}}

Finally in the CreateEmployeeComponent class include the following saveEmployee() method. At the moment we are simply logging the value of the Angular generated Form model to the console. In our upcoming videos, we will discuss how to save the new employee to a database table. 

saveEmployee(employeeForm: NgForm): void {
  console.log(employeeForm.value);
}

Please note : Make sure to import NgForm type from '@angular/forms'
import { NgForm } from '@angular/forms';

Remember we discussed, The ngForm directive supplements the form element with additional features and properties like value, dirty, touched, valid etc. To see all these properties, knock of the value property and log just the employeeForm as shown below.

saveEmployee(employeeForm: NgForm): void {
  console.log(employeeForm);
}

At this point, if you fill in the Full Name and Email text boxes and when you submit the form either by click the "Save" button or by pressing the "Enter" key you will see the form logged to the browser console and you can see all these properties.
angular forms example

These properties are greatly useful for performing form validation. We will discuss them in detail in our upcoming videos.

Vid link
Suggested Videos
Part 3 - Angular routing and navigation | Text | Slides
Part 4 - Angular base href | Text | Slides
Part 5 - Angular forms tutorial | Text | Slides

In this video we will discuss working with radio buttons in Angular Template Driven forms.


We want to include "Gender" radio buttons in the Create Employee form as shown below. When we select employee "Gender" using the radio buttons, the selected gender value should reflect in the Angular generated form model as shown in the image below. Also, we we click the "Save" button we want the selected gender value to be logged to the console.
bootstrap radio buttons in Angular


To achieve this all you have to do is include the following HTML in create-employee.component.html file

<div class="form-group">
  <label>Gender</label>
  <div class="form-control">
    <label class="radio-inline">
      <input type="radio" name="gender" value="male" [(ngModel)]="gender">
      Male
    </label>
    <label class="radio-inline">
      <input type="radio" name="gender" value="female" [(ngModel)]="gender">
      Female
    </label>
  </div>
</div>

Code Explanation
While we are here, let's also include a textbox to capture "Phone Number" and "Contact Preference" radio button. So the form should now look as as shown below.
radio button and angular

For your referece, here is the complete HTML in create-employee.component.html 

<form #employeeForm="ngForm" (ngSubmit)="saveEmployee(employeeForm)">
  <div class="panel panel-primary">
    <div class="panel-heading">
      <h3 class="panel-title">Create Employee</h3>
    </div>
    <div class="panel-body">

      <div class="form-group">
        <label for="fullName">Full Name</label>
        <input id="fullName" type="text" class="form-control" name="fullName"
        [(ngModel)]="fullName">
      </div>

      <div class="form-group">
        <label for="email">Email</label>
        <input id="email" type="text" class="form-control" name="email"
        [(ngModel)]="email">
      </div>

      <div class="form-group">
        <label for="phoneNumber">Phone Number</label>
        <input id="phoneNumber" type="text" class="form-control" name="phoneNumber"
        [(ngModel)]="phoneNumber">
      </div>

      <div class="form-group">
        <label>Contact Preference</label>
        <div class="form-control">
          <label class="radio-inline">
            <input type="radio" name="contactPreference" value="email"
            [(ngModel)]="contactPreference">
            Email
          </label>
          <label class="radio-inline">
            <input type="radio" name="contactPreference" value="phone"
            [(ngModel)]="contactPreference">
            Phone
          </label>
        </div>
      </div>

      <div class="form-group">
        <label>Gender</label>
        <div class="form-control">
          <label class="radio-inline">
            <input type="radio" name="gender" value="male" [(ngModel)]="gender">
            Male
          </label>
          <label class="radio-inline">
            <input type="radio" name="gender" value="female" [(ngModel)]="gender">
            Female
          </label>
        </div>
      </div>
    </div>

    <div class="panel-footer">
      <button class="btn btn-primary" type="submit">Save</button>
    </div>
  </div>
</form>

Angular Generated Forom Model : {{employeeForm.value | json}}

Vid link
Suggested Videos
Part 4 - Angular base href | Text | Slides
Part 5 - Angular forms tutorial | Text | Slides
Part 6 - Bootstrap radio buttons in Angular | Text | Slides

In this video we will discuss

How to get a radio button checked by default in Angular : Consider the following HTML, that displays "Gender" radio buttons

<div class="form-group">
  <label>Gender</label>
  <div class="form-control">
    <label class="radio-inline">
      <input type="radio" name="gender" value="male" [(ngModel)]="gender" >
      Male
    </label>
    <label class="radio-inline">
      <input type="radio" name="gender" value="female" [(ngModel)]="gender">
      Female
    </label>
  </div>
</div>


If we include checked attribute on one of the radio buttons, we expect that radio button to be checked by default when the form initially loads. But you will discover that is not the case. In the following example, we have included "checked" attribute on "Male" radio button, but when the form is displayed it is not checked.

<input type="radio" name="gender" value="male" [(ngModel)]="gender" checked>

However, if you remove the "ngModel" directive from the radio button, then it gets checked as expected. Notice the "ngModel" directive is removed from the radio button.

<input type="radio" name="gender" value="male" checked>

With Angular Template Driven forms, we use "ngModel" directive for two-way data binding. So the moment we put it back in place the "checked" attribute does not work. To make it work include "gender" property in the component class and initialise to the value of the radio button that you want to have checked by default. In our case, let us say, we want the "Male" radio button to be checked by default. To achieve this include "gender" property initialised to value of "male" in the component class as shown below.

gender = 'male';

At this point you will have "Male" radio button checked by default when the form loads. Now, even if we remove the "checked" attribute from the "Male" radio button it is still checked by default when the form loads. This is because of the two-way data binding that we get with "ngModel" directive. For our form we do not want any radio button to be checked by default, so remove the "checked" attribute and the "gender" property from the component class.

How to disable a radio button : To disable a radio button, use the disabled attribute on that radio button. "Male" radio button in this case will be disabled when the form initially loads.

<input type="radio" name="gender" value="male" [(ngModel)]="gender" disabled>

Another important point to keep in mind. By default, disabled form controls are not included in the Angular auto generated form model. Since, the "Male" radio button is disabled, the gender property will not be included in the Angular generated form model.

In our form, we do not want any radio button to be disabled, so please remove the disabled attribute.

In our next video, we will discuss working with CheckBox control in Angular Template Driven forms.

Vid Link
Suggested Videos
Part 5 - Angular forms tutorial | Text | Slides
Part 6 - Bootstrap radio buttons in Angular | Text | Slides
Part 7 - Angular radio button checked by default | Text | Slides

In this video we will discuss 
  1. Working with a checkbox control in Angular Template Driven forms
  2. How to have a checkbox checked by default
  3. How to disable a checkbox

Working with a checkbox in Angular is very similar to working with a radio button. We want to include "Is Active" checkbox in the Create Employee form as shown below. When we check the checkbox, "isActive" property should reflect in the Angular generated for model as shown in the image below. Also, when we click the "Save" button we want the "isActive" property value to be logged to the console.
bootstrap checkbox in angular


To achieve this all you have to do is include the following HTML in create-employee.component.html file

<div class="form-group">
  <div class="form-control">
    <label class="checkbox-inline">
      <input type="checkbox" name="isActive" [(ngModel)]="isActive">Is Active
    </label>
  </div>
</div>

If we include "checked" attribute on a checkbox, we expect checkbox to be checked by default when the form initially loads. But you will discover that is not the case.
 

<input type="checkbox" name="isActive" [(ngModel)]="isActive" checked>Is Active

However, if you remove the "ngModel" directive from the checbox, then it gets checked as expected. Notice the "ngModel" directive is removed from the checkbox.

<input type="checkbox" name="isActive" checked>Is Active

With Angular Template Driven forms, we use "ngModel" directive for two-way data binding. So the moment we put it back in place the "checked" attribute does not work. To make it work include "isActive" property in the component class and initialise it to true.

isActive = true;

At this point you will have "Is Active" checkbox checked by default when the form loads. Now, even if we remove the "checked" attribute from the checkbox it is still checked by default when the form loads. This is because of the two-way data binding that we get with "ngModel" directive. For our form we do not want the checkbox to be checked by default, so remove the "checked" attribute and the "isActive" property from the component class.

How to disable a checkbox : To disable a checkbox, use the disabled attribute

<input type="checkbox" name="isActive" [(ngModel)]="isActive" disabled>Is Active

Another important point to keep in mind. By default, disabled form controls are not included in the Angular auto generated form model. Since, the "Is Active" checkbox is disabled, it will not be included in the Angular generated form model.

In our form, we do not want the checkbox to be disabled, so please remove the disabled attribute.

Vid Link


Angular bootstrap select list

Suggested Videos
Part 6 - Bootstrap radio buttons in Angular | Text | Slides
Part 7 - Angular radio button checked by default | Text | Slides
Part 8 - Bootstrap checkbox in angular | Text | Slides

In this video we will discuss 
  • Working with a select list in Angular Template Driven forms
  • How to have one of the select list option selected by default
  • How to disable select list

Let us understand working with a select element in Angular with a simple example. We want to include "Department" select list as shown in the image below.
angular bootstrap select list


Here is the HTML for the "Department" select list
<div class="form-group">
  <label for="department">Department</label>
  <select id="department" name="department"
          [(ngModel)]="department" class="form-control">
    <option value="1">Help Desk</option>
    <option value="2">HR</option>
    <option value="3">IT</option>
    <option value="4">Paroll</option>
  </select>
</div>

At the moment, we have hard coded the select list options in the HTML. In our next video we will discuss, how to get the select list options from the component class. Notice each option also has a corresponding value. The value is the department id which is what we want to save in the database table when the form is submitted. We will discuss, saving the data to a database table in a later video.

At this point, when we select an option, notice the corresponding option value is included against the "department" property in the Angular auto-generated form model.
angular dropdown selected value

Also notice, when we click the "Save" button, the "department" property along with the selected option value is logged to the console in browser developer tools.
angular select options example

How to have one of the select list option selected by default

If we include "selected" attribute on one of the options of the select list, we expect that option to be selected by default when the form initially loads. In the example below, we have included the "selected" attribute on the "IT" option, but when the form reloads, the "IT" option is not selected.

<option value="3" selected>IT</option>

If you remove the "ngModel" directive from the select list, then the the "IT" option gets selected as expected. Notice the "ngModel" directive is removed from the select list.

<div class="form-group">
  <label for="department">Department</label>
  <select id="department" name="department" class="form-control">
    <option value="1">Help Desk</option>
    <option value="2">HR</option>
    <option value="3" selected>IT</option>
    <option value="4">Paroll</option>
  </select>
</div>

In Angular, we use "ngModel" directive for two-way data binding. So the moment we put it back in place the "selected" attribute does not work. To make it work include "department" property in the component class and initialise it with one of the option value which you want to have selected by default. In our case, we want the "IT" option to be selected by default. The "IT" option value is "3". So, I have initialised "department" property with a value of '3'

department = '3'

At this point you will have "IT" option selected by default when the form loads. Now, even if we remove the "selected" attribute from the "IT" option, it is still selected by default when the form loads. This is because of the two-way data binding that we get with "ngModel" directive.

How to disable a select list : To disable a select element, use the disabled attribute

<select id="department" name="department" [(ngModel)]="department"
        class="form-control" disabled>

Another important point to keep in mind. By default, disabled form controls are not included in the Angular auto generated form model. Since, the "department" select element is disabled, it will not be included in the Angular generated form model.

In our form, we do not want the select element to be disabled, so please remove the disabled attribute. Also, we do not want any option to be selected by default, so remove the "department" property from the component class.

In our next video, we will discuss, how to get the select list options from the component class, instead of having them hard-coded in the HTML.

Vid link


Angular select options from array

Suggested Videos
Part 7 - Angular radio button checked by default | Text | Slides
Part 8 - Bootstrap checkbox in angular | Text | Slides
Part 9 - Angular bootstrap select list | Text | Slides




Step 1 : Create the Department class. 

Add a TypeScript file to the models folder. Name it department.model.ts. Copy and paste the following code. Notice the Department class has 2 properties - id and name of the department.

export class Department {
    id: number;
    name: string;
}


Step 2 : Import the Department class 

Include the following import statement in create-employee.component.ts file
import { Department } from '../models/department.model';

Step 3 : Include the following array of departments in CreateEmployeeComponent class in create-employee.component.ts file

departments: Department[] = [
  { id: 1, name: 'Help Desk' },
  { id: 2, name: 'HR' },
  { id: 3, name: 'IT' },
  { id: 4, name: 'Payroll' }
];

Please note : The "Department" type is not required for the application to work, but it adds great value during development. Using it provides us intellisense, error checking and type saftey.

Step 4 : In create-employee.component.html file, modify the HTML that displays the "Department" dropdownlist as shown below.

<div class="form-group">
  <label for="department">Department</label>
  <select id="department" name="department" [(ngModel)]="department"
          class="form-control">
    <option *ngFor="let dept of departments" [value]="dept.id">
      {{dept.name}}
    </option>
  </select>
</div>

Code explanation :
  • On the "option" element we are using ngFor structural directive to loop over the array of departments we have in the "departments" property of the component class
  • For each "Department" object in the "departments" array, we get an option.
  • The option value is the department id and the display text is the department name
  • Notice the square brackets around the [value] property. This is property binding in Angular. We discussed property binding in detail in Part 9 of Angular 2 tutorial. If you remove the square brackets the value for each option will be the literal text "dept.id" instead of the department id (1 or 2 or 3 etc.)
  • To display the deprtment name we are using interpolation. We discussed interpolation in Part 8 of Angular 2 tutorial.
  • Since ngFor is a structural directive there is an asterisk before it.
  • Structural directives modify the DOM, i.e they add or remove the elements from DOM. Adding and removing elements from DOM is different from showing and hiding. We will discuss all these in detail in our upcoming videos.
At this point, when we select a department, the respective department id is included in the Angular generated form model. Along the same lines, when we click the "Save" button the respective department id is logged to the console.

Please note : It is important that we include the ngFor directive on the element that we want to be repeated. In our case we want an option element for each department we have in the array. So we included the ngFor directive on the option element. If we instead include the ngFor directive on the "div" element that has the bootstrap "form-group" class as shown below.

<div class="form-group" *ngFor="let dept of departments">
  <label for="department">Department</label>
  <select id="department" name="department" [(ngModel)]="department"
          class="form-control">
    <option [value]="dept.id">
      {{dept.name}}
    </option>
  </select>
</div>

We get 4 department dropdownlists. That is one for each department in the array. So it is important we include the ngFor directive on the right element.
angular ngfor dropdown



Angular datepicker tutorial

Suggested Videos
Part 8 - Bootstrap checkbox in angular | Text | Slides
Part 9 - Angular bootstrap select list | Text | Slides
Part 10 - Angular select options from array | Text | Slides

In this video we will discuss
  • Why is not a good practice to use the browser built-in DatePicker control
  • Installing ngx-bootstrap 
  • Using ngx-bootstrap datepicker in Angular

Why is not a good practice to use the browser built-in DatePicker control : This is because the implementation of datepicker is different from browser vendor to vendor. This means our end users may have different experience depending on the browser they use. Let us understand this with an example.


On our "Create Employee" form we want to capture Date of Birth of an employee. Datepicker control is very useful in capturing dates from users. When we use the HTML5 input type date, the browser automatically displays it's built-in datepicker control. Include the following piece of HTML on "create-employee.component.html" file just below the "Department" field HTML

<div class="form-group">
  <label for="dateOfBirth">Date of Birth</label>
  <input id="dateOfBirth" name="dateOfBirth" [(ngModel)]="dateOfBirth"
          type="date" class="form-control" />
</div>

Notice we have set the input element type to date. At this point if we run the project and navigate to http://localhost:4200/create in Google chrome, we see the date-picker as shown below.
angular datepicker example

Now, if we navigate to the same url in firefox, we see a date-picker control that is very different from the date-picker control that is on Google chrome browser.
angular bootstrap datepicker

So, this means our end users have different experience depending on the browser they use. What we want here is consistency. There are many third party Date-picker controls that we can use, to provide consistent experience to our end users. ngx-bootstrap datepicker control is one of them.

Please refer to the UI components section on the following page, to see the list of all third party UI components that we can use in Angular
https://angular.io/resources

Installing ngx-bootstrap : The following are the steps to install ngx-bootstrap 

Step 1 : Execute the following command to npm install ngx-bootstrap
npm install ngx-bootstrap --save

Step 2 : If you do not have Bootstrap installed, please install it using the following npm command. If you are following along we have already installed bootstrap in Part 1 of this Angular CRUD tutorial. So I am not going to execute this command again.
npm install bootstrap@3 --save

Please note : We are usng Bootstrap 3. We can also use Bootstrap 4 with ngx-bootstrap. Please refer to the documentation available at the following link on how to use Bootstrap 4 with ngx-bootstrap.
https://valor-software.com/ngx-bootstrap/#/getting-started

Step 3 : Once Bootstrap is installed, open .angular-cli.json file and specify the path to the Bootstrap stylesheet (bootstrap.min.css) in the styles property as shown below. Again, we have already done this in Part 1 of.
"styles": [
  "../node_modules/bootstrap/dist/css/bootstrap.min.css",
  "styles.css"
]

Using ngx-bootstrap datepicker in Angular : The following are the steps to use ngx-bootstrap datepicker in Angular

Step 1 : In app.module.ts file, include the following import statement to import BsDatepickerModule 
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';

Also, include BsDatepickerModule in the imports array of @NgModule decorator as shown below
@NgModule({
  imports: [BsDatepickerModule.forRoot(),...]
})

Step 2 : In "create-employee.component.html" file, make the following 2 changes to the HTML that displays the "Date of Birth" field
  • Change the "type" attribute value from "date" to "text"
  • Include "bsDatepicker" directive on the input element
<div class="form-group">
  <label for="dateOfBirth">Date of Birth</label>
  <input id="dateOfBirth" name="dateOfBirth" [(ngModel)]="dateOfBirth"
          type="text" bsDatepicker class="form-control" />
</div>

Step 3 : Include a reference to the bs-datepicker.css file in .angular-cli.json file.

"styles": [
  "../node_modules/bootstrap/dist/css/bootstrap.min.css",
  "../node_modules/ngx-bootstrap/datepicker/bs-datepicker.css",
  "styles.css"
]

At this point when you view the page in Google chrome or Firefox, you get the same datepicker and hence the same experience.
angular datepicker tutorial

When we select a date from the date-picker control, the "Date of Birth" textbox is automatically populated with the selected date and it is also captured by the angular generated form model.

With this datepicker control, it is also very easy to capture a date range. For example, you have an open job role, and you want to capture a date range for accepting CV's, we can very easily do this. All we have to do is use bsDaterangepicker directive instead of bsDatepicker directive on the input element as shown below.

<div class="form-group">
  <label for="dateOfBirth">Date of Birth</label>
  <input id="dateOfBirth" name="dateOfBirth" [(ngModel)]="dateOfBirth"
          type="text" bsDaterangepicker class="form-control" />

</div>

The above simple change, will display Daterange picker as shown below. When we select a date range, the corresponding input field is automatically populated with the selected date range and it is also captured by the angular generated form model.
angular date range picker
  • At the moment, the Datepicker is using the default green theme. We want to change it to dark-blue theme, so it matches with the rest of the form.
  • The date is captured in the textbox in mm/dd/yyyy format. We want to change it to dd/mm/yyyy format
  • At the moment there is no default date. We want to set a default date
  • The input element is spanning across the entire width of the form. We want to limit it's width
Datepicker is a highly configurable component. We will discuss how to do all of the above in our next video.



Customise ngx-bootstrap datepicker

Suggested Videos
Part 9 - Angular bootstrap select list | Text | Slides
Part 10 - Angular select options from array | Text | Slides
Part 11 - Angular datepicker tutorial | Text | Slides

In this video we will discuss customising the ngx-bootstrap datepicker component with an example. This is continuation to Part 11. Please watch Part 11 from before proceeding.


At the moment we have date range picker. Use bsDatepicker directive instead of bsDaterangepicker directive on the input element so we can capture single date i.e the Date of Birth of the employee.

<div class="form-group">
  <label for="dateOfBirth">Date of Birth</label>
  <input id="dateOfBirth" name="dateOfBirth" [(ngModel)]="dateOfBirth"
          class="form-control" type="text" bsDatepicker  />
</div>


Changing ngx-bootstrap datepicker theme : At the moment, the Datepicker is using the default green theme. We want to change it to dark-blue theme, so it matches with the rest of the form. As of this recording ngx-bootstrap datepicker component has the following 6 color schemes.
  1. theme-default
  2. theme-green
  3. theme-blue
  4. theme-dark-blue
  5. theme-red
  6. theme-orange
We can change the default colour-scheme, by manipulating containerClass property in bsConfig object. Here are the steps.

Step 1 : Make the following changes in CreateEmployeeComponent class (i.e create-employee.component.ts file)

// Import BsDatepickerConfig type. This is the Config object for datepicker. Using this
// config object we can set minDate, maxDate, whether to show/hide week numbers and
// change the color theme using the containerClass property.
import { BsDatepickerConfig } from 'ngx-bootstrap/datepicker';

// In the CreateEmployeeComponent class make the following changes

export class CreateEmployeeComponent implements OnInit {
  // create a property of type Partial<BsDatepickerConfig>
  datePickerConfig: Partial<BsDatepickerConfig>;

  // In the constructor set containerClass property to the preferred theme
  constructor() {
    this.datePickerConfig = Object.assign({}, { containerClass: 'theme-dark-blue' });
   }

   // Rest of the code...
}

Please note : 
We are using the TypeScript partial type here to set only the "containerClass" property of BsDatepickerConfig object. To learn more about the partial type please refer to the following article.
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

Object.assign() copies the property values from one or more source objects to a target object. The target object is the first parameter and the rest are the sources. Object.assign() is useful for merging objects or cloning them shallowly.

Step 2 : In the view template (i.e in create-employee.component.html file) bind the "datePickerConfig" property in the component class we created above in Step 1, to the bsConfig input property.

<div class="form-group">
  <label for="dateOfBirth">Date of Birth</label>
  <input id="dateOfBirth" name="dateOfBirth" [(ngModel)]="dateOfBirth"
          class="form-control" type="text" bsDatepicker [bsConfig]="datePickerConfig" />
</div>

At this point, you should see the Datepicker using the dark-blue theme colour as shown below.
angular bootstrap datepicker theme

Showing or hiding week numbers : By default, the weeknumber are displayed. If you want to hide them, all you have to do is set "showWeekNumbers" boolean property to false in the config object as shown below. 

constructor() {
  this.datePickerConfig = Object.assign({},
    {
      containerClass: 'theme-dark-blue',
      showWeekNumbers: false
    });
}

You can find all the properties of the config object at the following page. 
https://github.com/valor-software/ngx-bootstrap/blob/development/src/datepicker/bs-datepicker.config.ts

Along the same lines we can also set the min and max dates. Please note that the month numbers start from 0 and not 1. So for January it is 0, February it is 1, so on and so forth.

constructor() {
  this.datePickerConfig = Object.assign({},
    {
      containerClass: 'theme-dark-blue',
      showWeekNumbers: true,
      minDate: new Date(2018, 0, 1),
      maxDate: new Date(2018, 11, 31),
    });
}

To change the date format, use dateInputFormat property of the config object. 

constructor() {
  this.datePickerConfig = Object.assign({},
    {
      containerClass: 'theme-dark-blue',
      showWeekNumbers: true,
      minDate: new Date(2018, 0, 1),
      maxDate: new Date(2018, 11, 31),
      dateInputFormat: 'DD/MM/YYYY'
    });
}

To set a default date, create a property (dateOfBirth) in the component class and set it to the default value you want. Since we are using 2 way databinding, the defualt date is displayed in the corresponding input field when them form loads. In this case we have set default date to January 30, 2018.

dateOfBirth: Date = new Date(2018, 0, 30);

At the moment, the "Date of Birth" input element is spanning across the entire width of the form. There are sevral options to limit it's width. One option is to use the Bootstrap row and grid classes (Example: col-md-4, col-md-5, etc...)

<div class="row">
  <div class="form-group col-md-4">
    <label for="dateOfBirth">Date of Birth</label>
    <input id="dateOfBirth"  name="dateOfBirth" [(ngModel)]="dateOfBirth"
           class="form-control" type="text" bsDatepicker
           [bsConfig]="datePickerConfig" />
  </div>
</div>

To control the placement of the Datepicker use the placement property. The allowed values are "top" | "bottom" | "left" | "right". The default is "bottom".

For our form we do not want a default date to be set. So please remove the dateOfBirth property from the component class. We also do not want minDate and maxDate, so delete these properties as well from the datePickerConfig object. Also delete, showWeekNumbers property as it is set to true by default. This means our datePickerConfig object in the constructor has just 2 properties (dateInputFormat and containerClass)

constructor() {
  this.datePickerConfig = Object.assign({},
    {
      containerClass: 'theme-dark-blue',
      dateInputFormat: 'DD/MM/YYYY'
    });
}



Angular ngif directive

Suggested Videos
Part 10 - Angular select options from array | Text | Slides
Part 11 - Angular datepicker tutorial | Text | Slides
Part 12 - Customise ngx-bootstrap datepicker | Text | Slides

In this video we will discuss
  • Angular ngIf structural directive with an example
  • How to prevent a button from submitting form

Here is what we want to do : When the Create Employee form first loads, we want to display a field to enter "Photo Path" and "Show Preview" button

ngif example in angular 2


For now, we will assume employee photo is already available in the assets/images folder. We will discuss uploading files in a later video in this series. 

Once the user has typed the photo path in the respective field, and when they click "Show Preview" button, we want to display the photo and the text on the button should change to "Hide Preview"

angular2 ngif

At this point when the employee clicks "Hide Preview" button, the photo should be hidden and the text on the button should change again back to "Show Preview".

ngif angular 4

Here are the steps to achieve this

Step 1 : First include an input field for capturing employee photo path. As we have set both the name property and ngModel directive to photoPath, Angular generated form model will create a property with name "photoPath" and keeps track of what is typed in the photoPath textbox.

<div class="form-group">
  <label for="photoPath">Photo Path</label>
  <input id="photoPath" type="text" class="form-control"
          name="photoPath" [(ngModel)]="photoPath">
</div>

Step 2 : Include image element to preview the employee photo. Notice we have set height and width to 200 pixles. Also notice we are binding the img element src property to the photoPath property.

<div class="form-group">
  <img [src]="photoPath" height="200" width="200" />
</div>

With the above 2 changes in place, view the page in the browser and launch browser developer tools. On the console tab, you will see the following error. This is because, when the form loads, photoPath property is null and we have bound it to the src property of the img element. 
Failed to load resource: the server responded with a status of 404 (Not Found)

At this point, as you start to type in the "Photo Path" textbox, you will see a 404 error logged to the console every time you type a character. This is because every time a character is typed, angular tries to bind the src property of the image element to the photoPath property, Since we have not completed typing the full valid photo path, Angular is not able to find the image and it logs a 404 error to the console. Once we complete typing the valid photo path, the photo is displayed.

ngif angular 4 example

Step 3 : We do not want to render the image element when the form first loads. So create a boolen property with name previewPhoto in the CreateEmployeeComponent class and initialise it to false.

previewPhoto = false;

Step 4 : In the view template (i.e in create-employee.component.html) file, include *ngIf structural directive on the image element. Notice the expression assigned to *ngIf directive. It is the boolean property (previewPhoto) we created in the component class. If the value of the expression is truthy then the image element is rendered in the DOM otherwise it is not. Since we have initialised previewPhoto with false, the image element will not be rendered when the form is initially loaded.

<img [src]="photoPath" height="200" width="200" *ngIf="previewPhoto"/>

At this point, view the page in the browser and launch browser developer tools. On the console tab, you will not see any errors on the initial form load. Also, when you start to type in the Photo Path field, you do not see any 404 errors in spite of having the img element bound to photoPath property. This is because the *ngIf structural directive prevented the img element from being added to the DOM as it's value is falsy

Step 5 : Now we need to include a button to Show and Hide Image Preview. In the view template, include the following HTML.

<div class="form-group">
  <button (click)="togglePhotoPreview()" class="btn btn-primary">
    {{previewPhoto ? "Hide " : "Show " }} Preview
  </button>
</div>

Code explanation : 
  • On the button click, we are calling "togglePhotoPreview()" method. This is event binding. We discussed Event Binding in Part 14 of Angular 2 tutorial
  • We have not created togglePhotoPreview() method. We will create it in out next step.
  • We are using the Bootstrap btn and btn-primary classes for styling
  • We are using interpolation to dynamically change the button text. 
Step 6 : In the component class, create togglePhotoPreview() method. Notice this method toggles the value of previewPhoto property.

togglePhotoPreview() {
  this.previewPhoto = !this.previewPhoto;
}
  • At this point, view the page in the browser and launch browser developer tools. Type a valid photo path and click "Show Preview" button.
  • The image will be displayed and the text on the button changes to "Hide Privew" as expected.
  • If you look on the console tab, you will see that the Angular generated form model is logged to the console. We did not expect this to happen. 
  • The code to log the employee form values is in the saveEmployee() method and this method should only be called when we click the "Save" button.
  • So the question that comes to our mind is, why is the form being submitted when we click "Show Preview" or "Hide Preview" button.
  • This is because of the way we have created the button. If we do not explicitly specify the button type attribute, the button behaves like the "Submit" button and hence the code in the "saveEmployee()" method is also executed.
  • To prevent this, explicitly set the type attribute of the button to "button". This prevents the button from behaving as a Submit button.
<div class="form-group">
  <button type="button" (click)="togglePhotoPreview()" class="btn btn-primary">
    {{previewPhoto ? "Hide " : "Show " }} Preview
  </button>
</div>



Angular disable browser validation

Suggested Videos
Part 11 - Angular datepicker tutorial | Text | Slides
Part 12 - Customise ngx-bootstrap datepicker | Text | Slides
Part 13 - Angular ngif directive | Text | Slides

In this video we will discuss the following
  • By default Angular 4 and later versions disable browser native validation. How to enable browser validation using ngNativeValidate directive
  • How to explicitly disable the native browser validation using the novalidate attribute if you are using Angular 2.
  • Why is it better to disable browser built-in validation and use Angular to validate instead

To understand browser native validation, 
  1. On the "Create Employee" view template, include required attribute on FullName input field 

  2. Navigate to the "Create Employee" form and launch browser developer tools.  

  3. Do not type anything in the "Full Name" input field click the "Save" button.

  4. Notice we do not get any validation, in spite of having required attribute on the "Full Name" input field.

  5. This is because by default, Angular 4 and later versions disable browser validation by including novalidate attribute on the form tag.

  6. To confirm this, click on the "Elements" tab in the browser developer tools and you will see "novalidate" attribute on the form tag

  7. If you want to enable browser validation, include ngNativeValidate directive on the form tag in create-employee.component.html file

    <form #employeeForm="ngForm" ngNativeValidate
          (ngSubmit)="saveEmployee(employeeForm)">

  8. At this point, if you click the "Save" button without typing anything in the Full Name field, the native browser validation kicks in and you will see "Please fill in this field" validation error. At the moment I am using Google Chrome browser.

    angular disable browser validation

  9. Now if you view the same page in a different browser like Firefox for example, you will have a different experience. The browser validation is displayed in Firefox as shown below.

    angular disable html5 validation

  10. Because of this inconsistency it is better to disable browser native validation and use Angular instead to validate form fields. We will discuss validaing form fields using Angular in our upcoming videos.

  11. By default, browser built-in validation is disabled if you are using Angular 4 or any later version.

  12. At the moment, we are using Angular version 5 and want to keep browser validation disabled, so remove the ngNativeValidate directive from the form tag.

  13. If you are using Angular 2, you will have to explicitly disable browser validation by using novalidate attribute on the form tag.

Why is it better to disable browser built-in validation and use Angular to validate instead
Different browser vendors implement browser validation differently and as a result, the end users have different experience depending on the browser they use. Because of this inconsistency it is better to disable browser native validation and use Angular instead to validate form fields. 

Next video : We will discuss validating form fields using Angular



Angular disable browser validation

Suggested Videos
Part 11 - Angular datepicker tutorial | Text | Slides
Part 12 - Customise ngx-bootstrap datepicker | Text | Slides
Part 13 - Angular ngif directive | Text | Slides

In this video we will discuss the following
  • By default Angular 4 and later versions disable browser native validation. How to enable browser validation using ngNativeValidate directive
  • How to explicitly disable the native browser validation using the novalidate attribute if you are using Angular 2.
  • Why is it better to disable browser built-in validation and use Angular to validate instead

To understand browser native validation, 
  1. On the "Create Employee" view template, include required attribute on FullName input field 

  2. Navigate to the "Create Employee" form and launch browser developer tools.  

  3. Do not type anything in the "Full Name" input field click the "Save" button.

  4. Notice we do not get any validation, in spite of having required attribute on the "Full Name" input field.

  5. This is because by default, Angular 4 and later versions disable browser validation by including novalidate attribute on the form tag.

  6. To confirm this, click on the "Elements" tab in the browser developer tools and you will see "novalidate" attribute on the form tag

  7. If you want to enable browser validation, include ngNativeValidate directive on the form tag in create-employee.component.html file

    <form #employeeForm="ngForm" ngNativeValidate
          (ngSubmit)="saveEmployee(employeeForm)">

  8. At this point, if you click the "Save" button without typing anything in the Full Name field, the native browser validation kicks in and you will see "Please fill in this field" validation error. At the moment I am using Google Chrome browser.

    angular disable browser validation

  9. Now if you view the same page in a different browser like Firefox for example, you will have a different experience. The browser validation is displayed in Firefox as shown below.

    angular disable html5 validation

  10. Because of this inconsistency it is better to disable browser native validation and use Angular instead to validate form fields. We will discuss validaing form fields using Angular in our upcoming videos.

  11. By default, browser built-in validation is disabled if you are using Angular 4 or any later version.

  12. At the moment, we are using Angular version 5 and want to keep browser validation disabled, so remove the ngNativeValidate directive from the form tag.

  13. If you are using Angular 2, you will have to explicitly disable browser validation by using novalidate attribute on the form tag.

Why is it better to disable browser built-in validation and use Angular to validate instead
Different browser vendors implement browser validation differently and as a result, the end users have different experience depending on the browser they use. Because of this inconsistency it is better to disable browser native validation and use Angular instead to validate form fields. 

Next video : We will discuss validating form fields using Angular



Displaying angular form validation error messages

Suggested Videos
Part 13 - Angular ngif directive | Text | Slides
Part 14 - Angular disable browser validation | Text | Slides
Part 15 - Angular form validation | Text | Slides

In this video we will discuss
  • How to display validation error messages to the user
  • Style the error messages using Bootstrap 
  • How to disable Submit button if the form is not valid

This is continuation to Part 15. Please watch Part 15 from Angular CRUD tutorial before proceeding.


Here is what we want to do. If the "Full Name" field is not valid we want to style the input field with a red border. The associated label text should also turn red and "Full Name is required" validation error message should be displayed.

angular validate required field

Once we type something in the Full Name field, and when it becomes valid, the validation message and the red broder should disappear and also the label text should return to it's normal black colourcolour.

angular form validation required

We will be using the Bootstrap framework for styling validation error messages. If you are new to Bootstrap, please check out our Bootstrap tutorial by clicking here.

We discussed Bootstrap form validation states in Part 23 of Bootstrap tutorial. We will use the following Bootstrap classes for styling validation error messages.
  • has-error
  • control-label
  • help-block
Modify the "Full name" input filed as shown below.

<div class="form-group" [class.has-error]="fullNameControl.invalid">
  <label for="fullName" class="control-label">Full Name</label>
  <input id="fullName" required type="text" class="form-control" name="fullName"
         [(ngModel)]="fullName" #fullNameControl="ngModel">
  <span class="help-block" *ngIf="fullNameControl.invalid">
    Full Name is required
  </span>
</div>

Code explanation :
  • [class.has-error]="fullNameControl.invalid. This is class binding in angular. If the invalid property returns true, then the Bootstrap class has-error is added to the div element, if it is false then the class is removed.

  • On the "Full Name" label element we applied control-label Bootstrap class. This class turns the label text to red if there is a validation error.

  • *ngIf="fullNameControl.invalid". The *ngIf structural directive on the span element adds or removes the validation error message depending on the invalid property value. If the invalid property is true, then the validation error message is displayed, otherwise it is removed. Also, notice we are using the Bootstrap help-block class on the span element for styling.
At this point, save the changes and view the page in the browser. Notice when the form initially loads, we see the validation error message Full Name is required and it is also styled as expected. As we soon as we start typing, the error goes away. When we delete everything that we have typed, the error appears again. So, it's working as expected.

Let's enhance this a bit more. Some users does not like to see the validation error messages, even before they had the opportunity to touch the form field. So what we want to do is, 
  • Do not display any validation error messages when the form is initially loaded. 
  • When the user touches the field, and if he leaves the field without typing in the value, then we want to display the validation error message. 
This is easy. You might have already guessed we could use touched property to achieve this. So modify the Full Name field HTML as shown below. With this change, the validation error message is displayed only when the Full Name field is invalid and touched.

<div class="form-group"
     [class.has-error]="fullNameControl.invalid && fullNameControl.touched">
  <label for="fullName" class="control-label">Full Name</label>
  <input id="fullName" required type="text" class="form-control" name="fullName"
         [(ngModel)]="fullName" #fullNameControl="ngModel">
  <span class="help-block"
        *ngIf="fullNameControl.invalid && fullNameControl.touched">
    Full Name is required
  </span>
</div>

To take this to the next level, we can style a valid field with a different colour. Here is what I mean.

bootstrap angular validation messages
  • When the form first loads, the Full Name and it's label are black in colour and the validation error message is not displayed
  • When the user touches the field and leaves it without typing anything, the colour changes to red and the validation error message is displayed
  • If the user types something, the field is valid, so we want a green border and the label text should also turn green.
To achieve this we can use the Bootstrap has-success class as shown below. As you can see, the has-success class is added when valid property is true and it is removed when it is false. 

<div class="form-group"
     [class.has-error]="fullNameControl.invalid && fullNameControl.touched"
     [class.has-success]="fullNameControl.valid">

As you can see these angular validation properties (valid, touched, dirty etc.) provide lot of power and flexibility when validating form fields and displaying validation error messages.

How to disable Submit button if the form is not valid : To disable the "Save" button when the form is not valid, bind the invalid property of the employeeForm template variable to the disabled property of the button.

<button class="btn btn-primary" type="submit"
[disabled]="employeeForm.invalid">Save</button>

Video Link


Model binding in angular template driven forms

Suggested Videos
Part 14 - Angular disable browser validation | Text | Slides
Part 15 - Angular form validation | Text | Slides
Part 16 - Displaying angular form validation error messages | Text | Slides

In this video we will discuss
  • Binding Angular form to our own model class
  • We will also discuss, how to fix one of the common error that we get when exporting ngModel into a local variable. The error that we get is, cannot assign to a reference or variable.

At the moment, in CreateEmployeeComponent we are using the Angular Auto-generated form model. Instead of using the Angular generated form model, we can use our model class.


In employee.model.ts file in the models folder, we have Employee class. We want to use this class as the model when creating a new employee. Here are the steps.

Step 1 : In create-employee.component.ts file, import the Employee model
import { Employee } from '../models/employee.model';

Step 2 : In CreateEmployeeComponent class, include employee property. Notice we have set the type to Employee and initialised all properties with NULL value.

export class CreateEmployeeComponent implements OnInit {
  employee: Employee = {
    id: null,
    name: null,
    gender: null,
    contactPreference: null,
    phoneNumber: null,
    email: null,
    dateOfBirth: null,
    department: null,
    isActive: null,
    photoPath: null
  };

Step 3 : In the view template, bind the ngModel directive of an input field to it's corresponding property on the employee object. The employee property we created in Step 2 returns an employee object, which is the model for our form.

For example, bind ngModel directive on the email input field to the email property on the employee object.
[(ngModel)]="employee.email"

Except fullName, bind the ngModel directive of the rest of the input fields with the corresponding properties on the employee object.

In the employee class we do not have fullName property. we have name instead. On the view template, the corresponding input field name is fullName. To keep things consistent let's change fullName to name on the label and the input field as shown below.

<div class="form-group" [class.has-error]="name.invalid && name.touched">
  <label for="name" class="control-label">Name</label>
  <input id="name" required type="text" class="form-control" name="name"
         [(ngModel)]="name" #name="ngModel">
  <span class="help-block" *ngIf="name.invalid && name.touched">
    Name is required
  </span>
</div>

At this point, if you view the page in the browser, you will see the following error.
Cannot assign to a reference or variable

We get this error because, Angular generated form model creates name property and we are also creating a local template variable with the same name by exporting ngModel to #name. Hence we get the error - Cannot assign to a reference or variable.

One way to fix this error is, by giving our local template reference variable a different name other than name. So if we change #name="ngModel" to #nameControl="noModel" the error goes away. We discussed this in detail in Part 15 of Angular CRUD tutorial.

The other way to fix this error is by using our own model. Using the ngModel directive, bind the name property of the employee object to the name input field

[(ngModel)]="employee.name"

At this point, if you view the page in the browser and notice the error is gone and all the properties in the Angular generated form model are NULL as expected.

To see our own employee model, include the following code in the view template file (create-employee.component.html)

Angular Generated Forom Model : {{employeeForm.value | json}}
<br/>
<br/>
Our Employee Model : {{ employee | json}}

At this point, on the browser we should see both - Angular generated form model and our own employee model. Notice as we change the values in the input fields, the respective properties in both the models are updated as expected.

At the moment, when we click the "Save" button, we are logging the employeeForm.value to the console. We instead want to log our employee model object. To do this 
In the view template, pass the employee object to the saveEmployee() method.

<form #employeeForm="ngForm" (ngSubmit)="saveEmployee(employee)">

Modify saveEmployee() method in create-employee.component.ts file as shown below.

saveEmployee(newEmployee: Employee): void {
  console.log(newEmployee);
}

At this point, when we click the Save button, the employee object is logged to the console as expected.

Video Link


Angular email validation example

Suggested Videos
Part 15 - Angular form validation | Text | Slides
Part 16 - Displaying angular form validation error messages | Text | Slides
Part 17 - Model binding in angular template driven forms | Text | Slides

In this video we will discuss 
  • Validating Email form field in Angular
  • Using multiple validators on a single input field
  • Angular safe navigation operator

Email validation in Angular : There are 2 different ways to validate email form field in Angular. We can either use pattern validator or email validator. Email validator is introduced in Angular 4. So if you are using Angular 4 or later version you may use email validator or pattern validator to validate email. If you are using Angular 2, then your only choice is to use Pattern validator.


In this video we will discuss using the Angular built-in Email validator and in our next video we will discuss using the Pattern validator

Consider the following HTML. Notice we are using Bootstrap classes for styling.

<div class="form-group">
  <label for="email">Email</label>
  <input id="email" type="text" class="form-control" name="email"
          [(ngModel)]="employee.email">
</div>

The above HTML would produce the following Email input field
angular email validation example

We want to validate this email input field for 2 things
  • Email is required and
  • Valid email must be provided
To make email, a required field modify the HTML as shown below

<div class="form-group" [class.has-error]="email.invalid && email.touched">
  <label for="email" class="control-label">Email</label>
  <input id="email" required type="text" class="form-control" name="email"
          [(ngModel)]="employee.email" #email="ngModel">
  <span class="help-block" *ngIf="email.invalid && email.touched">
    Email is required
  </span>
</div>

Code Explanation : 
  • [class.has-error]="email.invalid && email.touched". This is class binding in angular. If the email field is touched and invalid, then the Bootstrap class has-error is added to the div element, else the class is removed.
  • On the label that displays "Email" text, we applied control-label Bootstrap class. This class turns the label text to red if there is a validation error.
  • *ngIf="email.invalid && email.touched". Notice the *ngIf structural directive on the span element. If the email field is touched and invalid the span element is added to the DOM, else it is removed. The Bootstrap help-block class on the span element is for styling.
At this point, if you touch the email field and leave it without typing in anything, you will see the validation error message "Email is required"

angular 4 email validation example

We also want to make sure the user enters a valid email. If someone types ABC, that is not a valid email. Angular 4 has built-in email validator, that we can use to validate if the user has entered a valid email. Here are the steps.

Step 1 : On the email input field, place the email directive

<input id="email" required email

Step 2 : Use the following HTML, to display the validation error message. If the email is invalid, angular attaches email key to the errors collection. On the other hand, if the email field is valid, the key email will not be in the errors collection. The question mark here is called the safe navigation operator. It protects against null and undefined values in property paths. It is generally used when we are not sure if a property exists or not. It safely handles null and undefined values, and very useful to prevent null-reference exceptions.

<span class="help-block" *ngIf="email.errors?.email && email.touched">
  Email is Invalid
</span>

Here is the complete HTML that makes the email filed required and also checks if the email has a valid format

<div class="form-group" [class.has-error]="email.invalid && email.touched">
  <label for="email" class="control-label">Email</label>
  <input id="email" required email type="text" class="form-control" name="email"
          [(ngModel)]="employee.email" #email="ngModel">
  <span class="help-block" *ngIf="email.errors?.required && email.touched">
    Email is required
  </span>
  <span class="help-block" *ngIf="email.errors?.email && email.touched">
    Email is Invalid
  </span>
</div>

As of this recording, email validator provided by Angular does not allow null or empty values. When we leave the email field empty, the email validator is still fired. This is wrong. Checking NULL and empty values should be the job of the required validator. The following is the work around.

Bind email directive to a boolean expression. The email validator is only added when the email field value is not an empty string. This ensures that, when we type something in the email field, the email validator is attached to the input field and it validates if the email format is valid or not.

<input id="email" required [email]="employee.email!==''"

Please note : Do not forget to initialise the email property in the employee object to an empty string.

Next video : Using pattern validator to validate email in Angular

Video Link


Angular regular expression validation

Suggested Videos
Part 16 - Displaying angular form validation error messages | Text | Slides
Part 17 - Model binding in angular template driven forms | Text | Slides
Part 18 - Angular email validation example | Text | Slides

In this video we will discuss using pattern validator in angular to meet most of your application complex validation requirements. 


With the pattern validator we use a regular expression. Regular expressions are extremely useful when you want to validate if a given string conforms to a specified pattern. 

For example, you can use regular expressions to check if a given email conforms to a a valid email format. Similarly you can also check if provided postcode conforms to a specific country postcode format. 

Apart from checking conformity with a pattern, they can also be used to extract sub-strings from a given input string.


To validate if the provided email has a valid email pattern we can use the pattern validator in angular. To use the pattern validator use the pattern attribute along with the regular expression on the input field you want to validate.

<input pattern="^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$" type="text"
       name="email" [(ngModel)]="employee.email" #email="ngModel">

It is easy to learn regular expressions. Initially they may appear complicated, but if you get the basics right it is very easy to understand them. However, you can also find the commonly used regular expressions on the internet. For example, if you want to find a regular expression to validate email address, simply search the internet with the following string
Regular expression for email validation

Use the following HTML, to display the validation error message. If the email is invalid, angular attaches pattern key to the errors collection. On the other hand, if the email field is valid, the key pattern will not be in the errors collection. The question mark here is called the safe navigation operator. We discussed this operator in detail in our previous video. If you are new to this operator, please check out our previous video.

<span class="help-block" *ngIf="email.errors?.pattern && email.touched">
  Email is Invalid
</span>

The following example, shows both required and pattern validators on the Email input field.

<div class="form-group" [class.has-error]="email.invalid && email.touched">
  <label for="email" class="control-label">Email</label>
  <input required pattern="^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
         id="email" type="text" class="form-control" name="email"
         [(ngModel)]="employee.email" #email="ngModel">
  <span class="help-block" *ngIf="email.errors?.required && email.touched">
    Email is required
  </span>
  <span class="help-block" *ngIf="email.errors?.pattern && email.touched">
    Email is Invalid
  </span>
</div>

Let's take this pattern validation to the next level. I want to validate emails against a specific domain. For example pragimtech.com is the only valid domain that I want to allow. Any other domain should be considered invalid. This can be very easily achieved with the following regular expression.

^[a-zA-Z0-9_.+-]+@(?:(?:[a-zA-Z0-9-]+\.)?[a-zA-Z]+\.)?(pragimtech)\.com$

Video Link


Angular radio button validation

Suggested Videos
Part 17 - Model binding in angular template driven forms | Text | Slides
Part 18 - Angular email validation example | Text | Slides
Part 19 - Angular regular expression validation | Text | Slides

In this video we will discuss radio button validation in Angular with example


Example :  Gender is a required field. If one of the gender radio button is not checked, we want to validate and display "Gender is required" validation error message.

angular 2 radio button validation


As soon as one of the "Gender" radio button is selected, the validation error message should disappear.

angular radio button validation

Here is the HTML that makes this possible.

<div class="form-group" [class.has-error]="gender.invalid">
  <label class="control-label">Gender</label>
  <div class="form-control">
    <label class="radio-inline">
      <input type="radio" name="gender" required #gender="ngModel"
             value="male" [(ngModel)]="employee.gender"> Male
    </label>
    <label class="radio-inline">
      <input type="radio" name="gender" required #gender="ngModel"
             value="female" [(ngModel)]="employee.gender"> Female
    </label>
  </div>
  <span class="help-block" *ngIf="gender.invalid">
    Gender is required
  </span>
</div>

Code Explanation : 
  • Notice we have required attribute on both the radio buttons (Male and Female). This attribute makes the "Gender" field required.
  • #gender="ngModel". This creates a template reference variable. We can now this variable (gender) to check if the field is invalid. Notice #gender="ngModel" is placed on the both the radio buttons.
  • [class.has-error]="gender.invalid". This class binding adds the has-error bootstrap css class when the field is invalid and removes it when the field is valid. This class is used for styling the validation error messages.
  • On the label element that displays the static text "Gender" we have "control-label" class. This class turns the text "Gender" to red when there is a validation error.
  • *ngIf="gender.invalid". Notice the *ngIf structural directive on the span element. If the gender field is invalid the span element is added to the DOM, else it is removed. The Bootstrap help-block class on the span element is for styling.
The span element that displays the validation error message can also be coded as shown below. Notice, instead of using "gender.invalid" as the expression for *ngIf, we are using "gender.errors?.required". When the required validation fails, Angular attaches the required key to the errors collection property of the gender field. The key is removed if the field passes validation. So we can check for the existence of this key, to control the display of the validation error message.

<span class="help-block" *ngIf="gender.errors?.required">
  Gender is required
</span>

Video Link
\

Add required attribute dynamically in angular

Suggested Videos
Part 18 - Angular email validation example | Text | Slides
Part 19 - Angular regular expression validation | Text | Slides
Part 20 - Angular radio button validation | Text | Slides

In this video we will discuss, how to add required attribute dynamically in template driven forms. In our upcoming videos we will discuss how to do the same in reactive forms.


Example : Consider the following 3 fields.

angular 2 conditional validation


If "Email" is selected as the "Contact Preference", then "Email" input field is required.

cross field validation angular 4

If "Phone" is selected as the "Contact Preference", then "Phone" input field is required.

angular conditional validation

Contact Preference radio buttons HTML : 
<div class="form-group" [class.has-error]="contactPreference.invalid">
  <label class="control-label">Contact Preference</label>
  <div class="form-control">
    <label class="radio-inline">
      <input type="radio" required #contactPreference="ngModel" name="contactPreference"
              value="email" [(ngModel)]="employee.contactPreference"> Email
    </label>
    <label class="radio-inline">
      <input type="radio" required #contactPreference="ngModel" name="contactPreference"
              value="phone" [(ngModel)]="employee.contactPreference"> Phone
    </label>
  </div>
  <span class="help-block" *ngIf="contactPreference.errors?.required">
      Contact Preference is required
  </span>
  <!-- Delete the below line after you see
      the selected value in the browser -->
  Contact Preference Selected Value : {{ contactPreference.value }}
</div>

Code Explanation : 
  • We made the contact preference field required, by including required attribute on both email and phone radio buttons.
  • At this point view the page in the browser and notice the selected radio button value. When email radio button is selected we see the selected value as email, and when phone radio button is selected, we see the selected value as phone.
  • We will use this selected contact preference radio button value (contactPreference.value) to dynamically add or remove required attribute to phone and email input fields.
Email input field HTML : 

<div class="form-group" [class.has-error]="email.invalid">
  <label for="email" class="control-label">Email</label>
  <input id="email" [required]="contactPreference.value=='email'"
          type="text" class="form-control"
          pattern="^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
          [(ngModel)]="employee.email" #email="ngModel" name="email">
  <span class="help-block" *ngIf="email.errors?.required">
    Email is required
  </span>
  <span class="help-block" *ngIf="email.errors?.pattern && email.touched">
    Email is Invalid
  </span>
</div>

Code explanation : 
  • Notice the required attribute. We assigned it a boolean expression (contactPreference.value=='email'). 
  • This boolean expression dynamically adds or removes required attribute to the email field depending on whether email contact preference radio button is selected or not.
Phone Number input field HTML : Notice the boolean expression assigned to the required attribute. This boolean expression dynamically adds or removes required attribute to the phone number field depending on whether phone contact preference radio button is selected or not.

<div class="form-group" [class.has-error]="phoneNumber.invalid">
  <label for="phoneNumber" class="control-label">Phone Number</label>
  <input id="phoneNumber" [required]="contactPreference.value=='phone'"
          #phoneNumber="ngModel" class="form-control" type="text"
          name="phoneNumber" [(ngModel)]="employee.phoneNumber">
  <span class="help-block" *ngIf="phoneNumber.errors?.required">
    Phone Number is required
  </span>
</div>

Video Link


Angular checkbox validation

Suggested Videos
Part 19 - Angular regular expression validation | Text | Slides
Part 20 - Angular radio button validation | Text | Slides
Part 21 - Add required attribute dynamically in angular | Text | Slides

In this video we will discuss checkbox validation in Angular with example. 


We want to make the following "Is Active" check box a required field. If the checkbox is not checked, we want to validate and display "Is Active is required" validation error message. As soon as the checkbox is checked, the validation error message should disappear.

angular checkbox validation


Consider the following HTML

<div class="form-group" [class.has-error]="isActive.invalid && isActive.touched">
  <div class="form-control">
    <label class="checkbox-inline control-label">
      <input type="checkbox" required name="isActive"
             #isActive="ngModel" [(ngModel)]="employee.isActive">
      Is Active
    </label>
  </div>
  <span class="help-block"
        *ngIf="isActive.errors?.required && isActive.touched">
    Is Active is required
  </span>
</div>

Code Explanation : 
  • The required attribute makes "Is Active" field required.
  • #isActive="ngModel". This creates a template reference variable. We can now this variable (isActive) to check if the field is invalid, touched, dirty etc. 
  • [class.has-error]="isActive.invalid && isActive.touched". This class binding adds the has-error bootstrap css class when the field is invalid and touched and removes it when the field is valid. This class is used for styling the validation error messages.
  • On the label element that displays the static text "Is Active" we have "control-label" class. This class turns the text "Is Active" to red when there is a validation error.
  • *ngIf="isActive.errors?.required && isActive.touched". Notice the *ngIf structural directive on the span element. If the "Is Active" field fails required validation and touched, the span element is added to the DOM, else it is removed. The Bootstrap help-block class on the span element is for styling.
At this point, 
  • If you tab into the checkbox control and leave it, without checking it, you will see the validation error message
  • If you select the checkbox box, the error goes away
  • If you unselecet the checkbox, the required validation error appears again
This implementation of the checkbox validation is useful, when you want to force the user to select a checkbox. For example, on many web sites, you might have seen a checkbox with the following text. Only when you agree by checking that checkbox, you will be able to proceed. Otherwise you will have to cancel that specific action.
I Agree to the terms and conditions

What if the employee is terminated or resigned? In that case we do not want the checkbox to be checked. But at the moment, the required validator is forcing us to have the checkbox checked. To fix this modify the required attribute as shown below. Notice, we are binding a boolean expression to the required attribute. If the expression is true the required validator is attached, otherwise it is removed.

[required]="employee.isActive==null"

With this change
  • When the form first loads, isActive property on the employee object is null. So the required attribute is attached to the checkbox.
  • If we tab into the checkbox and levae it without selecting it, we see the required validation error message as expected
  • If we select the checkbox box, the error goes away
  • If we unselecet the checkbox, notice we don't get the required validation. This is because, when the checkbox is unchecked, the value of isActive property on the employee object is false and not NULL. So the boolean expression bound to the required attribute returns false. Hence the required attribute is removed from the checkbox field and we do not see the required validation error.
At the moment, the user interface is confusing. If the employee you are creating is not active, you have to first check the (Is Active) checkbox and then un-check it. To make this less confusing there 2 options for us.
  • Remove the required validator on the (Is Active) checkbox, and treat NULL as false. 
  • Use 2 radio buttons (Yes or No), instead of a single checkbox.
Video Link


Angular select list validation

Suggested Videos
Part 20 - Angular radio button validation | Text | Slides
Part 21 - Add required attribute dynamically in angular | Text | Slides
Part 22 - Angular checkbox validation | Text | Slides

In this video, we will discuss Dropdown list validation in Angular with example. 


Example : We want to make "Department" Dropdownlist a required field. If a department is not selected, we want to validate and display "Department is required" validation error message. As soon as a department is checked, the validation error message should disappear.

angular select list validation


Consider the following HTML : 

<div class="form-group"
     [class.has-error]="department.touched && department.invalid">
  <label for="department" class="control-label">Department</label>
  <select id="department" required #department="ngModel"
          name="department" [(ngModel)]="employee.department"
          class="form-control">
    <option *ngFor="let dept of departments" [value]="dept.id">
      {{dept.name}}
    </option>
  </select>
  <span class="help-block"
        *ngIf="department.touched && department.invalid">
    Department is required
  </span>
</div>

Code Explanation : 
  • The required attribute makes "Department" field required.
  • #department="ngModel". This creates a template reference variable. We can now this variable (department) to check if the field is invalid, touched, dirty etc. 
  • [class.has-error]="department.touched && department.invalid". This class binding adds the has-error bootstrap css class when the field is invalid and touched and removes it when the field is valid. This class is used for styling the validation error messages.
  • On the label element that displays the static text "Department" we have "control-label" class. This class turns the text "Department" to red when there is a validation error.
  • *ngIf="department.touched && department.invalid". Notice the *ngIf structural directive on the span element. If the "Department" field fails required validation and touched, the span element is added to the DOM, else it is removed. The Bootstrap help-block class on the span element is for styling.
At this point, the dropdown list validation works as expected. However, in most of the real world applications, you might see one of the following options as the first option in a dropdown list. 
  • Please select 
  • Select Department 
  • etc...
Modify the HTML to include "Select Department" as the first option. Notice the value of this option is set to '-1', to indicate that it is not a valid department selection. The change is highlighted in YELLOW.

<div class="form-group"
     [class.has-error]="department.touched && department.invalid">
  <label for="department" class="control-label">
    Department
  </label>
  <select id="department" required #department="ngModel" name="department"
          [(ngModel)]="employee.department" class="form-control">
    <option value="-1">Select Department</option> 
    <option *ngFor="let dept of departments" [value]="dept.id">
      {{dept.name}}
    </option>
  </select>
  <span class="help-block"
        *ngIf="department.touched && department.invalid">
    Department is required
  </span>
</div>

In the component class (create-employee.component.ts), initialise department property with a value of '-1'. This will ensure that, when the "Department" dropdownlist is loaded, the first default option 'Select Department' is selected.

employee: Employee = {
  id: null,
  name: null,
  gender: null,
  contactPreference: null,
  phoneNumber: null,
  email: '',
  dateOfBirth: null,
  department: '-1',
  isActive: null,
  photoPath: null
};

At this point, view the page in the browser. The dropdownlist REQUIRED validation does not work as expected. The default first option, 'Select Department' is treated as a valid department selection. We will discuss, how to fix this in our next video.

Video Link


angular value vs ngvalue

Suggested Videos
Part 21 - Add required attribute dynamically in angular | Text | Slides
Part 22 - Angular checkbox validation | Text | Slides
Part 23 - Angular select list validation | Text | Slides

In this video we will discuss how to validate a select element if it has a custom option like one of the following.
  • Please Select
  • Select Department
  • Etc...

Consider the following example :

<div class="form-group"
     [class.has-error]="department.touched && department.invalid">
  <label for="department" class="control-label">Department</label>
  <select required #department="ngModel" name="department"
          [(ngModel)]="employee.department" id="department"
          class="form-control">
    <option [ngValue]="null">Select Department</option>
    <option *ngFor="let dept of departments" [value]="dept.id">
      {{dept.name}}
    </option>
  </select>
  <span class="help-block"
        *ngIf="department.touched && department.errors?.required">
    Department is required
  </span>
</div>


Code explanation : 
  • <option [ngValue]="null">Select Department</option>. Notice we are using ngValue instead of value. If you use value, null is treated as a string and not as a null. Hence the required validation does not work. Along with using ngValue, also make sure you set the department property on the employee model object to null.
  • <option *ngFor="let dept of departments" [value]="dept.id">{{dept.name}}</option>. Here we are using value instead of ngValue, because we just want the selected department id as a string. If you want the department object itself instead of just the department id string, then use ngValue.
  • <option *ngFor="let dept of departments" [ngValue]="dept">{{dept.name}}</option>. In this example we are using ngValue and binding it to the dept object. If we select a department now, we get the selected department object.
    "department": { "id": 3, "name": "IT" }
  • Use the disabled attribute, if you do not want the user to be able to select the "Select Department" option.
    <option disabled [ngValue]="null">Select Department</option>
Please note :  The built-in required validator will only work with the SELECT element, if the default option value is null.
<option disabled [ngValue]="null">Select Department</option>

In a real world application, most of the time we load the SELECT list options from a database table. In some case we may also load the default option (like SELECT DEPARTMENT etc) also from the database. In this case the default option value may not be NULL. Depending on your use case it could be -1, or SELECT or something else. So in scenarios like this, built-in required validator does not work with the SELECT element. To make it work, we have to implement our own custom required validator. We will discuss how to do this in our next video.

Video Link


Angular custom validator example template driven forms

Suggested Videos
Part 22 - Angular checkbox validation | Text | Slides
Part 23 - Angular select list validation | Text | Slides
Part 24 - Angular value vs ngValue | Text | Slides

In this video, we will discuss creating a custom validator in angular with an example. We will make this validator reusable and configurable. Along the way, we will also learn how to create a custom directive in angular.


Example : When you have a default option like "Select Department" in a SELECT list, the REQUIRED validation does not work, if the default option value is anything else other than NULL. So if the default option value is not null, then that default option is also treated as a valid selection, and we do not get to see the required validation error. If "Select Department" is selected, we want the validation to fail, and display "Department is required" validation error message. To make this work the way we want, we implement a custom validator. 

angular select custom validation


Create a custom Directive 
To use a custom validator in template driven forms, we have to create the validator as a directive. Once we have the directive created, we can then use that directive as an attribute on the select element that we want to validate. This is going to be a configurable and reusable validator. We can use it with any SELECT list in an angular application. So create a "shared" folder in the "app" folder. In the "shared" folder create a file with name "select-required-validator.directive.ts". Copy and paste the folllowing code. 

import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
import { Directive } from '@angular/core';

@Directive({
    selector: '[appSelectValidator]',
    providers: [
        {
            provide: NG_VALIDATORS,
            useExisting: SelectRequiredValidatorDirective,
            multi: true
        }]
})
export class SelectRequiredValidatorDirective implements Validator {
    validate(control: AbstractControl): { [key: string]: any } | null {
        return control.value === '-1' ? { 'defaultSelected': true } : null;
    }
}

Code Exaplanation : 
Since we are creating a directive, we decorate the class with @Directive decorator

NG_VALIDATORS is a collection of validators. It already contains all the built-in validators like required, pattern etc. Before we can use our custom validator we have to add it to the list of validators by adding it to NG_VALIDATORS token. To specify that we want to add our validator to the list of validators, we set multi property to true

providers: [
    {
        provide: NG_VALIDATORS,
        useExisting: SelectRequiredValidatorDirective,
        multi: true
    }]

Implement Validator interface as we are creating a custom validator
export class SelectRequiredValidatorDirective implements Validator

Since we are implementing validator interface, we have to provide implementation for the interface validate() method. This method has one input parameter and it's type is AbstractControl. AbstractControl extends both FormControl and FormGroup. In some cases you may want to validate a Formgroup instead of a single FormControl. So to cater for both scenarios, the parent type - AbstractControl is specified. This function returns an object if the validation fails or null if the validation succeeds. The object that is returned when the validation fails contains a key/value pair. The key is a string and the value can be anything.
validate(control: AbstractControl): { [key: string]: any } | null

If the selected value in the SELECT list is the default value (-1), then we return an object with key 'defaultSelected' and value of true to indicate that the validation has failed. Otherwise we return NULL to indicate validation succeeded. In the HTML we can use the "defaultSelected" key to display the validation error specific to this custom validator.
return control.value === '-1' ? { 'defaultSelected': true } : null;

Import the custom directive in a module where you want to use it. 

At the moment we only have one module - Root module. So in app.module.ts file include the following import statement
import { SelectRequiredValidatorDirective } from './shared/select-required-validator.directive';

Also include SelectRequiredValidatorDirective in the declarations array of the NgModule() decorator

Using the custom required validator on the SELECT element

Modify the "Department" SELECT element in create-employee.component.html file as shown below.

<div class="form-group"
     [class.has-error]="department.touched && department.errors?.defaultSelected">
  <label for="department" class="control-label">Department</label>
  <select id="department" #department="ngModel" name="department"
          [(ngModel)]="employee.department" appSelectValidator
          class="form-control">
    <option value="-1">Select Department</option>
    <option *ngFor="let dept of departments" [value]="dept.id">
      {{dept.name}}
    </option>
  </select>
  <span class="help-block"
        *ngIf="department.touched && department.errors?.defaultSelected">
    Department is required
  </span>
</div>

Code Explanation : 
  • [class.has-error]="department.touched && department.errors?.defaultSelected". Notice, in this conditional class binding we are using the key "defaultSelected" to style the Department SELECT element and it's label when there is a validation error. This key is set by the required custom validator when the validation fails.
  • *ngIf="department.touched && department.errors?.defaultSelected". Notice here also we are using the key "defaultSelected" to display the validation error message.
  • appSelectValidator is the selector we gave for our custom validation directive and we are using it as an attribute on the SELECT list that we want to validate.
At the moment, we can only use this custom validator with a SELECT list whose default option value is -1. We will discuss how to make this custom validator configurable and reusable in our next video.

Video Link


Angular select list required custom validator

Suggested Videos
Part 23 - Angular select list validation | Text | Slides
Part 24 - Angular value vs ngValue | Text | Slides
Part 25 - Angular custom validator example template driven forms | Text | Slides

In this video we will discuss, how to make the select list custom required validator configurable and reusable. This is continuation to Part 25. Please watch Part 25 from Angular CRUD tutorial before proceeding.


Here is the SELECT list custom required validator we implemented in our previous video

import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
import { Directive } from '@angular/core';

@Directive({
    selector: '[appSelectValidator]',
    providers: [{
        provide: NG_VALIDATORS,
        useExisting: SelectRequiredValidatorDirective,
        multi: true
    }]
})
export class SelectRequiredValidatorDirective implements Validator {
    validate(control: AbstractControl): { [key: string]: any } | null {
        return control.value === '-1' ? { 'defaultSelected': true } : null;
    }
}


Consider this line of code : Notice we have hard-coded the default option value '-1'. Because of this hard-coded value, we will not be able to reuse this validator with another SELECT list if it has a different default option value other than '-1'. 

return control.value === '-1' ? { 'defaultSelected': true } : null;

To make this custom validator reusable, we want to be able to do pass the default option value from the template to our custom validator as shown below. Notice we are using our custom validator selector and passing it the default option value. In this case we are passing -101. If you have another SELECT list, and if it's default option value is -1, you simply pass that value.
<select appSelectValidator="-101" #department="ngModel" ....>

For this to work, we have to create a corresponding input property in the custom validator class. Modify SelectRequiredValidatorDirective as shown below. The changes are commented and self-explanatory

import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
// Import input from @angular/core package
import { Directive, Input } from '@angular/core';

@Directive({
    selector: '[appSelectValidator]',
    providers: [{
        provide: NG_VALIDATORS,
        useExisting: SelectRequiredValidatorDirective,
        multi: true
    }]
})
export class SelectRequiredValidatorDirective implements Validator {
    // Create input property to receive the
    // specified default option value
    @Input() appSelectValidator: string;
    validate(control: AbstractControl): { [key: string]: any } | null {
        // Remove the hard-coded value and use the input property instead
        return control.value === this.appSelectValidator ?
                                    { 'defaultSelected': true } : null;
    }
}

Please note : Since this is a directive input property, the input property name and the selector name must match. 
@Input() appSelectValidator: string;

For some reason if you do not like the input property name, you can use an alias as shown below. 
@Input('appSelectValidator') defaultValue: string;

We are now able to specify the default option value using the directive input property. This makes our custom validator configurable and reusable. We can now use this custom required validator to validate any SELECT list in our Angular application.

Video Link


Angular password and confirm password validation

Suggested Videos
Part 24 - Angular value vs ngValue | Text | Slides
Part 25 - Angular custom validator example template driven forms | Text | Slides
Part 26 - Angular select list required custom validator | Text | Slides

In this video we will discuss how to compare password and confirm password fields and validate if they are equal. If they are not equal we want to display "Password and Confirm Password does not match" validation error.

angular confirm password validation


This is also commonly called as cross field validation in angular. We cannot use any of the buil-in angular validators to perform cross-field validation. So let's create a custom validator. To use a custom validator in template driven forms, we create the validator as a directive. We discussed creating custom validators and directives in Parts 25 and 26 of Angular CRUD tutorial. If you are new to these concepts, please check out those videos.

We will make this custom validator a reusable validator, so we could use it to compare any 2 input fields for equality. For example, we can use this same custom validator to compare if EMAIL and CONFIRM EMAIL fields are equal.


Create a custom Directive 
Add a new TypeScript file to the "shared" folder. Name it confirm-equal-validator.directive.ts.Copy and paste the folllowing code. 

import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
import { Directive, Input } from '@angular/core';

@Directive({
    selector: '[appConfirmEqualValidator]',
    providers: [{
        provide: NG_VALIDATORS,
        useExisting: ConfirmEqualValidatorDirective,
        multi: true
    }]
})
export class ConfirmEqualValidatorDirective implements Validator {
    @Input() appConfirmEqualValidator: string;
    validate(control: AbstractControl): { [key: string]: any } | null {
        const controlToCompare = control.parent.get(this.appConfirmEqualValidator);
        if (controlToCompare && controlToCompare.value !== control.value) {
            return { 'notEqual': true };
        }

        return null;
    }
}

Code Exaplanation : 
Since we are creating a directive, we decorate the class with @Directive decorator

This selector will be used as a directive on one of the 2 input fields that we want to compare for equality. In our case we will use it on the Confirm Password field.
selector: '[appConfirmEqualValidator]',

NG_VALIDATORS is a collection of validators. It contains all the built-in validators like required, pattern etc. Before we can use our custom validator we have to add it to the list of validators by adding it to NG_VALIDATORS token. To specify that we want to add our validator to the list of validators, we set multi property to true

providers: [{
    provide: NG_VALIDATORS,
    useExisting: ConfirmEqualValidatorDirective,
    multi: true
}]

Implement Validator interface as we are creating a custom validator
export class ConfirmEqualValidatorDirective implements Validator

Since our custom validator class is implementing validator interface, we have to provide implementation for the interface validate() method. This method has one input parameter and it's type is AbstractControl. AbstractControl extends both FormControl and FormGroup. In some case you may want to validate a Formgroup instead of a single FormControl. So to cater for both scenarios, the parent type - AbstractControl is specified. This function returns an object if the validation fails or null if the validation succeeds. The object that is returned when the validation fails contains a key/value pair. The key is a string and the value can be anything.
validate(control: AbstractControl): { [key: string]: any } | null

The following line creates an input property. Since this is a directive input property, the input property name and the selector name must match. 
@Input() appConfirmEqualValidator: string;

We will use this custom directive (appConfirmEqualValidator), as an attribute either on the PASSWORD field or CONFIRM PASSWORD FIELD. If we use this on the  CONFIRM PASSWORD field, we will also pass the field that we want to compare with. In this case the PASSWORD field.

So the input property that we have created above receives the control that we want to compare CONFIRM PASSWORD field with. This input property prevents the need to hard code the name of the control that we want to compare with. Hence it makes our custom validator reusable. We can use it to compare any 2 input fields for equality.

<input name="confirmPassword" appConfirmEqualValidator="password"
  • In the validate() method implementation, we first retrieve the control that we want to compare CONFIRM PASSWORD field with. That field in our case is the PASSWORD field.
  • Both PASSWORD and CONFIRM PASSWORD fields are siblings. So to get the PASSWORD field, we go one level up from the CONFIRM PASSWORD field using the parent property. The parent property returns the root FormGroup. 
  • On the root FormGroup we call the get() method passing it, the input property. The input property receives the name of the PASSWORD field
  • Finally we check if the PASSWORD and CONFIRM PASSWORD filed values are equal. If they are equal, we return NULL indication validation succeeded otherwise we return an object with key=notEqual and value=true.
  • In the HTML we can use this key (notEqual) to display the relevant validation error message
validate(control: AbstractControl): { [key: string]: any } | null {
    const controlToCompare = control.parent.get(this.appConfirmEqualValidator);
    if (controlToCompare && controlToCompare.value !== control.value) {
        return { 'notEqual': true };
    }

    return null;
}

Import the custom directive in a module where you want to use it. 

At the moment we only have one module - Root module. So in app.module.ts file include the following import statement
import { ConfirmEqualValidatorDirective } from './shared/confirm-equal-validator.directive';

Also include ConfirmEqualValidatorDirective in the declarations array of the NgModule() decorator

Using the custom validator

Include the following HTML for Password and Confirm Password fields in create-employee.component.html file as shown below.

<div class="form-group"
     [class.has-error]="password.touched && password.invalid">
  <label for="password" class="control-label">Password</label>
  <input id="password" required type="text" class="form-control"
         name="password" [(ngModel)]="employee.password"
         #password="ngModel">
  <span class="help-block"
        *ngIf="password.touched && password.errors?.required">
    Password is required
  </span>
</div>

<div class="form-group"
     [class.has-error]="confirmPassword.touched && confirmPassword.invalid">
  <label for="confirmPassword" class="control-label">Confirm Password</label>
  <input name="confirmPassword" appConfirmEqualValidator="password" required
         id="confirmPassword" type="text" class="form-control"
         [(ngModel)]="employee.confirmPassword" #confirmPassword="ngModel">
  <span class="help-block"
        *ngIf="confirmPassword.touched && confirmPassword.errors?.required">
    Confirm Password is required
  </span>
  <span class="help-block"
        *ngIf="confirmPassword.touched && confirmPassword.errors?.notEqual &&
          !confirmPassword.errors?.required">
    Password and Confirm Password does not match
  </span>
</div>

Notice on the CONFIRM PASSWORD field we are using our custom directive and passing it the name of the control (PASSWORD) that we want to compare with.
<input name="confirmPassword" appConfirmEqualValidator="password"

Notice the expression of *ngIf structural directive. We are using the key (notEqual) set by our custom validator to display the validation error message.
<span class="help-block"
      *ngIf="confirmPassword.touched && confirmPassword.errors?.notEqual &&
        !confirmPassword.errors?.required">
  Password and Confirm Password does not match
</span>

At the moment there are 2 problems with our custom validator
When the validation fails only the CONFIRM PASSWORD field is styled with red border and not the PASSWORD field. We want the password field also to have the red border.

Angular password and confirm password validation

If you first change PASSWORD field and then the CONFIRM PASSWORD field, the validation works as expected. Now if you go back and change the PASSWORD field, the validation will not be triggered and you will not see the validation error even if the passwords do not match. 

We will discuss why this is happening and how to fix it in our next video.

Video Link


Angular trigger validation manually

Suggested Videos
Part 25 - Angular custom validator example template driven forms | Text | Slides
Part 26 - Angular select list required custom validator | Text | Slides
Part 27 - Angular password and confirm password validation | Text | Slides

In this video we will discuss
  1. How to add or remove validation styles to a group of elements in Angular
  2. How to trigger validation manually in Angular using the updateValueAndValidity() function

This is continuation to Part 27. Please watch Part 27 from Angular CRUD tutorial before proceeding.

How to add and remove validation styles to a group of elements in Angular : Use the ngModelGroup directive and group the elements. Now we can add or remove validation styles from the group. This in turn adds or removes the validation styles from all the elements in that group.


In our case, we want to group password and confirm password fields to be able to control their validation styles. Notice in the example below, both password and confirm password fields are grouped using the ngModelGroup directive. The bootstrap validation class has-error is conditionally added or removed from the group.

<div ngModelGroup="passwordGroup"
     [class.has-error]="confirmPassword.touched && confirmPassword.invalid">

  <div "passwordFieldDiv"> ...
  </div>
  <div "confirmPasswordFieldDiv"> ...
  </div>

</div>

Use of updateValueAndValidity() function : At the moment we have a problem with confirm password field validation. It does not work in one of the scenarios. Here is the scenario.

If you first change PASSWORD field and then the CONFIRM PASSWORD field, the validation works as expected. Now if you go back and change the PASSWORD field, the validation will not be triggered and you will not see the validation error even if the passwords do not match.

This is because our custom validation directive is applied on the confirm password filed but not on the password. So our custom validation is triggered only when the confirm password field is changed and not when the password field is changed. To make this work, even when the password field is changed, we have to tell confirm password field to run it's validation when password field is changed.

So the obvious question that comes to our mind is, how to tell the confirm password field to run it's validation?
Well updateValueAndValidity() function comes to the rescue. When this method is called on a control, that control's validation logic is executed again. Notice the event binding in the example below. The change event of the password field triggers a call to confirm password field's 
updateValueAndValidity() function. This in turn runs the confirm password field validation.

<input name="password"
      (change)="confirmPassword.control.updateValueAndValidity()" …>

The change event is fired only after the form control has lost focus. The input event is fired as the user changes the value. So if you want the validation to trigger as the user is changing the value, use the input event instead of change event.

Video Link


Angular trigger validation manually

Suggested Videos
Part 25 - Angular custom validator example template driven forms | Text | Slides
Part 26 - Angular select list required custom validator | Text | Slides
Part 27 - Angular password and confirm password validation | Text | Slides

In this video we will discuss
  1. How to add or remove validation styles to a group of elements in Angular
  2. How to trigger validation manually in Angular using the updateValueAndValidity() function

This is continuation to Part 27. Please watch Part 27 from Angular CRUD tutorial before proceeding.

How to add and remove validation styles to a group of elements in Angular : Use the ngModelGroup directive and group the elements. Now we can add or remove validation styles from the group. This in turn adds or removes the validation styles from all the elements in that group.


In our case, we want to group password and confirm password fields to be able to control their validation styles. Notice in the example below, both password and confirm password fields are grouped using the ngModelGroup directive. The bootstrap validation class has-error is conditionally added or removed from the group.

<div ngModelGroup="passwordGroup"
     [class.has-error]="confirmPassword.touched && confirmPassword.invalid">

  <div "passwordFieldDiv"> ...
  </div>
  <div "confirmPasswordFieldDiv"> ...
  </div>

</div>

Use of updateValueAndValidity() function : At the moment we have a problem with confirm password field validation. It does not work in one of the scenarios. Here is the scenario.

If you first change PASSWORD field and then the CONFIRM PASSWORD field, the validation works as expected. Now if you go back and change the PASSWORD field, the validation will not be triggered and you will not see the validation error even if the passwords do not match.

This is because our custom validation directive is applied on the confirm password filed but not on the password. So our custom validation is triggered only when the confirm password field is changed and not when the password field is changed. To make this work, even when the password field is changed, we have to tell confirm password field to run it's validation when password field is changed.

So the obvious question that comes to our mind is, how to tell the confirm password field to run it's validation?
Well updateValueAndValidity() function comes to the rescue. When this method is called on a control, that control's validation logic is executed again. Notice the event binding in the example below. The change event of the password field triggers a call to confirm password field's 
updateValueAndValidity() function. This in turn runs the confirm password field validation.

<input name="password"
      (change)="confirmPassword.control.updateValueAndValidity()" …>

The change event is fired only after the form control has lost focus. The input event is fired as the user changes the value. So if you want the validation to trigger as the user is changing the value, use the input event instead of change event.

Video Link


Angular 5 services tutorial

Suggested Videos
Part 27 - Angular password and confirm password validation | Text | Slides
Part 28 - Angular trigger validation manually | Text | Slides
Part 29 - Angular form group validation | Text | Slides

In this video we will discuss creating a service in angular. Whether you are using Angular 2, Angular 4 or Angular 5, the steps to create a service are the same. We discussed the basics of Angular services and why we need services in detail in Parts 25, 27 and 34 of Angular 2 tutorial. If you are new to services in Angular, please check out those videos by clicking here.


Creating a service

Add a new TypeScript file to the "employees" folder and name it employee.service.ts. Copy and paste the following code. At the moment we have the data hard-coded in the service method. In a later video we will discuss retrieving data from a remote server using HTTP. 


import { Injectable } from '@angular/core';
import { Employee } from '../models/employee.model';

// The @Injectable() decorator is used to inject other dependencies
// into this service. As our service does not have any dependencies
// at the moment, we may remove the @Injectable() decorator and the
// service works exactly the same way. However, Angular recomends
// to always use @Injectable() decorator to ensures consistency
@Injectable()
export class EmployeeService {
    private listEmployees: Employee[] = [
        {
            id: 1,
            name: 'Mark',
            gender: 'Male',
            contactPreference: 'Email',
            email: 'mark@pragimtech.com',
            dateOfBirth: new Date('10/25/1988'),
            department: 'IT',
            isActive: true,
            photoPath: 'assets/images/mark.png'
        },
        {
            id: 2,
            name: 'Mary',
            gender: 'Female',
            contactPreference: 'Phone',
            phoneNumber: 2345978640,
            dateOfBirth: new Date('11/20/1979'),
            department: 'HR',
            isActive: true,
            photoPath: 'assets/images/mary.png'
        },
        {
            id: 3,
            name: 'John',
            gender: 'Male',
            contactPreference: 'Phone',
            phoneNumber: 5432978640,
            dateOfBirth: new Date('3/25/1976'),
            department: 'IT',
            isActive: false,
            photoPath: 'assets/images/john.png'
        },
    ];

    getEmployees(): Employee[] {
        return this.listEmployees;
    }
}

Registering the service

A service in angular can be registered in a component or in a module. When a service is registered at a component level, then that service is available only to that component and any of it's children. It's not available to the other components. 

One the other hand, if we register a service at a module level, then that service is registered with the root injector and available to all the components in our application. We want our EmployeeService to be available in several components (like employee list component, edit component etc). So let's register it in the root module - AppModule.

We discussed dependency injection and injectors in Parts 32, 33, 35 and 36 in Angular 2 tutorial. If you are new to injectors and dependency injection in Angular, please check out those videos by clicking here.

Include the following import statement to import EmployeeService in app.module.ts file
import { EmployeeService } from './employees/employee.service';

Also make sure to include EmployeeService in the providers array of @NgModule decorator.

Injecting and using the service

We need the employee service we created above in ListEmployeesComponent. So let's import and use the Employee service in ListEmployeesComponent. Modify the code in list-employees.component.ts file as shown below. 

import { Component, OnInit } from '@angular/core';
import { Employee } from '../models/employee.model';
// Import EmployeeService
import { EmployeeService } from './employee.service';

@Component({
  templateUrl: './list-employees.component.html',
  styleUrls: ['./list-employees.component.css']
})
export class ListEmployeesComponent implements OnInit {
  employees: Employee[];

  // Inject EmployeeService using the constructor
  // The private variable _employeeService which points to
  // EmployeeService singelton instance is then available
  // throughout the class and can be accessed using this keyword
  constructor(private _employeeService: EmployeeService) { }

  // Call the getEmployees() service method of EmployeeService
  // using the private variable _employeeService
  ngOnInit() {
    this.employees = this._employeeService.getEmployees();
  }
}

Important points to remember about Angular service
  • A service in angular is a class
  • Irrespective of whether a service has an injected dependency or not, always decorate the angular service class with @Injectable() decorator for consistency and future proof
  • If a service is registered at a component level, then that service is available only to that component and to it's children
  • If a service is registered at a module level, then that service is available to all the components in the application
  • To use a service in a component inject it into the component class constructor
In our next video, we will discuss creating a new Employee.

Video Link


Create operation in angular

Suggested Videos
Part 28 - Angular trigger validation manually | Text | Slides
Part 29 - Angular form group validation | Text | Slides
Part 30 - Angular 5 services tutorial | Text | Slides

In this video we will discuss creating a new employee using the Create Employee form. This is continuation to Part 30. Please watch Part 30 from Angular CRUD tutorial before proceeding.


Modify EmployeeService to include save() method

Include the following save() method in EmployeeService in employee.service.ts file. At the moment, the save() method just pushes the employee object into the employees array. In a later video, we will discuss saving the employee to a database table by calling a web service over http.


save(employee: Employee) {
    this.listEmployees.push(employee);
}

Injecting and using EmployeeService in CreateEmployeeComponent

Make the following changes in create-employee.component.ts file

Include the following import statement to import EmployeeService
import { EmployeeService } from './employee.service';

Also, import Angular Router service. We will use this service's navigate() method to redirect the user to the employee list page after saving the employee.
import { Router } from '@angular/router';

Inject EmployeeService and Router service into the CreateEmployeeComponent using it's constructor.
constructor(private _employeeService: EmployeeService,
            private _router: Router)

Modify saveEmployee() method as shown below. Notice the saveEmployee() method calls the EmployeeService save() method passing it the employee object we want to save. Wait a minute, the employee object has all it's properties initialised to NULL. How do we get the values from the controls on the form to the properties of this employee object.

Well, we do not have to write any code to keep employee object properties and the form control values in sync. Angular's two way data-binding does that for us automatically.

Finally, we redirect the user to the "list" route using the navigate() method of the angular Router service.

saveEmployee(): void {
  this._employeeService.save(this.employee);
  this._router.navigate(['list']);
}

Also, modify the call to saveEmployee() method in create-employee.component.html file as shown below. Notice we removed the employee object that was being passed as a paramter.

<form #employeeForm="ngForm" (ngSubmit)="saveEmployee()">

At the moment, there is a small issue with data on the employee list page. Notice for the existing employees the department name is displayed where as for the new employeees department id is displayed. We will discuss how to fix this in our next video.

Video Link


Angular switch case example

Suggested Videos
Part 29 - Angular form group validation | Text | Slides
Part 30 - Angular 5 services tutorial | Text | Slides
Part 31 - Create operation in angular | Text | Slides

In this video, we will discuss angular ngSwitch directive. Let us understand switch case with an example. Switch case in angular is a combination of 3 directives
  • ngSwitch directive
  • ngSwitchCase directive
  • ngSwitchDefault directive

Consider the following department data. Depending on the employee's department id we want to display department name.

departments: Department[] = [
  { id: 1, name: 'Help Desk' },
  { id: 2, name: 'HR' },
  { id: 3, name: 'IT' },
  { id: 4, name: 'Payroll' }
];


ngSwitch example

<div [ngSwitch]="employee.department">
  <span *ngSwitchCase="1"> Help Desk </span>
  <span *ngSwitchCase="2"> HR </span>
  <span *ngSwitchCase="3"> IT </span>
  <span *ngSwitchCase="4"> Payroll </span>
  <span *ngSwitchDefault> N/A </span>
</div>

Code Explanation
  • [ngSwitch]="employee.department". The expression (employee.department) returns department id (1, 2 , 3 etc)
  • <span *ngSwitchCase="1"> Help Desk </span>. If the department id is 1, then this switchcase is executed and it displays Help Desk
  • <span *ngSwitchDefault> N/A </span>. The default switch case is executed if the department id is not 1, 2, 3 and 4
  • Jus like ngIf and ngFor, the directives ngSwicthCase and ngSwitchDefault are also structural directives, hence they have an asterisk in front of them
  • If multiple ngSwitchCases match the switch expression value, then all those ngSwitchCases are displayed
Video Link


Pass data from parent to child component in angular

Suggested Videos
Part 30 - Angular 5 services tutorial | Text | Slides
Part 31 - Create operation in angular | Text | Slides
Part 32 - Angular switch case example | Text | Slides

In this video we will discuss how to pass data from the Parent component to Child component using input properties. Let us understand this with an example.


At the moment the ListEmplyeesComponent displays the list of employees you see below.

Pass data from parent to child component in angular


At the moment, ListEmployeesComponent is doing 3 things
  • Calls the Angular EmployeeService to retrieve employees data
  • Loops through each employee
  • Has all the display logic to display employee details
Now let's create another component and off load the responsibility of displaying employee details to that component. Let's name this new component - DisplayEmployeeComponent

Here is the Angular CLI command you can use to generate the component
ng g c employees\DisplayEmployee --no-spec --flat

Copy and paste the following HTML in display-employee.component.html file

<div class="panel panel-primary">
  <div class="panel-heading">
    <h3 class="panel-title">{{employee.name}}</h3>
  </div>
  <div class="panel-body">
    <div class="col-xs-10">

      <div class="row vertical-align">

        <div class="col-xs-4">
          <img class="imageClass" [src]="employee.photoPath" />
        </div>
        <div class="col-xs-8">

          <div class="row">
            <div class="col-xs-6">
              Gender
            </div>
            <div class="col-xs-6">
              : {{employee.gender}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Date of Birth
            </div>
            <div class="col-xs-6">
              : {{employee.dateOfBirth | date}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Contact Preference
            </div>
            <div class="col-xs-6">
              : {{employee.contactPreference}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Phone
            </div>
            <div class="col-xs-6">
              : {{employee.phoneNumber}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Email
            </div>
            <div class="col-xs-6">
              : {{employee.email}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Department
            </div>
            <div class="col-xs-6" [ngSwitch]="employee.department"> :
              <span *ngSwitchCase="1"> Help Desk </span>
              <span *ngSwitchCase="2"> HR </span>
              <span *ngSwitchCase="3"> IT </span>
              <span *ngSwitchCase="4"> Payroll </span>
              <span *ngSwitchDefault> N/A </span>
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Is Active
            </div>
            <div class="col-xs-6">
              : {{employee.isActive}}
            </div>
          </div>

        </div>

      </div>
    </div>
  </div>
</div>

Notice in the HTML above we are binding to the employee property. We need to pass the employee object from the Parent component (ListEmployeesComponent) to this Component (DisplayEmployeeComponent). To make this happen we create an input property in DisplayEmployeeComponent. So modify the code in display-employee.component.ts file as shown below.

import { Component, OnInit, Input } from '@angular/core';
import { Employee } from '../models/employee.model';

@Component({
  selector: 'app-display-employee',
  templateUrl: './display-employee.component.html',
  styleUrls: ['./display-employee.component.css']
})
export class DisplayEmployeeComponent implements OnInit {
    // Parent component will use this Input property to pass
  // the employee object to which the template binds to
  @Input() employee: Employee;

  constructor() { }

  ngOnInit() {
  }
}

Copy and paste the following 2 style classes in display-employee.component.css file. Delete these 2 classes from list-employees.component.css. We do not need them there anymore.

.imageClass{
    width:200px;
    height:200px;
}
.vertical-align{
    display: flex;
    align-items: center;
}

Make the following changes in the parent component (list-employees.component.html). Notice, the child component selector (app-display-employee) is nested in the Parent component. The parent component, loops through each employee and passes the employee object to the child component (DisplayEmployeeComponent) using it's Input property.

<div *ngFor="let employee of employees">
  <app-employee-display [employee]="employee"></app-employee-display>
</div>

Video Link


Angular component input property change detection

Suggested Videos
Part 31 - Create operation in angular | Text | Slides
Part 32 - Angular switch case example | Text | Slides
Part 33 - Pass data from parent to child component in angular | Text | Slides

In this video we will discuss how to detect and react when component input property value changes. This is continuation to Part 33. Please watch Part 33 from Angular CRUD tutorial before proceeding.


To detect and react when an input property value changes, we have 2 options. We can either use
  • Property Setter
  • ngOnChanges Life Cycle Hook

If you are new to Angular Life Cycle hooks, please check out Part 24 from Angular 2 tutorial.

To understand these 2 approaches, let's modify ListEmployeesComponent as shown below. Notice instead of displaying all the employees at once, we have "View Next Employee" button which cycles through the list of employees, displaying one employee at a time.

angular component input property change detection

To achieve this modify the code in list-employees.component.html file as shown below.

<button (click)="nextEmployee()" class="btn btn-primary">
  View Next Employee
</button>
<br/><br/>
<app-employee-display [employee]="employeeToDisplay">
</app-employee-display>

Modify the code in list-employees.component.ts as shown below.

import { Component, OnInit } from '@angular/core';
import { Employee } from '../models/employee.model';
import { EmployeeService } from './employee.service';

@Component({
  templateUrl: './list-employees.component.html',
  styleUrls: ['./list-employees.component.css']
})
export class ListEmployeesComponent implements OnInit {
  employees: Employee[];
  employeeToDisplay: Employee;
  private arrayIndex = 1;

  constructor(private _employeeService: EmployeeService) { }

  ngOnInit() {
    this.employees = this._employeeService.getEmployees();
    this.employeeToDisplay = this.employees[0];
  }

  nextEmployee(): void {
    if (this.employeeToDisplay.id <= 2) {
      this.employeeToDisplay = this.employees[this.arrayIndex];
      this.arrayIndex++;
    } else {
      this.employeeToDisplay = this.employees[0];
      this.arrayIndex = 1;
    }
  }
}

At this point view the page in the browser. Notice only one employee is displayed. Click "View Next Employee" button to see the next employee. It is the child component (DisplayEmployeeComponent) that displays the employee details. For the child component to be able to display the employee details, the parent component is passing the employee object to the child component using the child component input property. 

So every time we click the "View Next Employee" button, the INPUT property value changes. When this happens we want to detect the change and react. Let us say for example, we want to log to the console the previously displayed employee name and the currently displayed employee name.

We can achieve this either by using ngOnChanges life cycle hook or Property Setter. Let's look at both the ways.

Detecting and reacting to Input property changes using ngOnChanges life cycle hook

// This life cycle hook receives SimpleChanges as an Input parameter
// We can use it to retrieve previous and current values as shown below
ngOnChanges(changes: SimpleChanges) {
  const previousEmployee = <Employee>changes.employee.previousValue;
  const currentEmployee = <Employee>changes.employee.currentValue;

  console.log('Previous : ' + (previousEmployee ? previousEmployee.name : 'NULL') );
  console.log('Current : ' + currentEmployee.name);
}

Next Video : Detecting and reacting to Input property changes using Property Setter

Video Link


Angular input change detection using property setter

Suggested Videos
Part 32 - Angular switch case example | Text | Slides
Part 33 - Pass data from parent to child component in angular | Text | Slides
Part 34 - Angular component input property change detection | Text | Slides

In this video we will discuss how to detect and react when component input property value changes using a property setter. This is continuation to Part 34. Please watch Part 34 from Angular CRUD tutorial before proceeding.


In our previous video we discussed, detecting and reacting to INPUT property changes using ngOnChanges life cycle hook. In this video we will discuss doing the same using a Property Setter instead.


Detecting and reacting to Input property changes using Property Setter


// Private backing field for the property
private _employee: Employee;

// This property setter is called anytime the input property changes
// Notice the code here logs the previous and current employee names
@Input()
set employee(val: Employee) {
  console.log('Previous : ' + (this._employee ? this._employee.name : 'NULL'));
  console.log('Current : ' + val.name);
  this._employee = val;
}

// This getter is called when reading and displaying data
get employee(): Employee {
  return this._employee;
}

At this point you might be thinking, there are 2 ways to detect and react to Input property changes (Property Setter and ngOnChanges life cycle hook). What is the difference between the two and when to use one over the other. We will answer these 2 questions in our next video.

Video Link


Angular property setter vs ngonchanges

Suggested Videos
Part 33 - Pass data from parent to child component in angular | Text | Slides
Part 34 - Angular component input property change detection | Text | Slides
Part 35 - Angular input change detection using property setter | Text | Slides

In our previous 2 videos we discussed 2 approaches (ngOnChanges and Property Setter) to detect and react to input property changes in Angular. In this video we will discuss the difference between these 2 approaches and when to use one over the other.


Both these approaches have their own use cases. Your software requirement determines which approach to choose. Let us understand this with an example.


Let us say your child component has 5 input properties. If any of the input properties change, then your requirement is to log those changes. This can be very easily achieved using ngOnChanges life cycle hook. The ngOnChanges life cycle hook is invoked when any of the input properties change. 

Each input property that has changed will be attached to the SimpleChanges object using the property name as the key. So if you have 5 input properties, and if 3 out of those 5 properties change, then those 3 properties will be attached to the SimpleChanges object using the property name as the key.

So in short, with ngOnChanges you have access to all input property changes at one place.

The following code logs all the input property changes to the browser console.

ngOnChanges(changes: SimpleChanges) {
  for (const propName of Object.keys(changes)) {

    const change = changes[propName];
    const from = JSON.stringify(change.previousValue);
    const to = JSON.stringify(change.currentValue);

    console.log(propName + ' changed from ' + from + ' to ' + to);
  }
}

To achieve this exact same thing (i.e logging if any of the 5 input properties change) with a property setter, is a bit tedious because you have to have that logging code in every property setter. So if you want to capture multiple property changes, I prefer ngOnChanges life cycle hook as we get all the changes  instead of just the changes related to a single property. On the other hand, if you are interested in a single property, then I would use a property setter instead.

private _employeeId: number;

@Input()
set employeeId(val: number) {
  console.log('employeeId changed from ' + JSON.stringify(this._employeeId)
    + ' to ' + JSON.stringify(val));
  this._employeeId = val;
}
get employeeId(): number {
  return this._employeeId;
}

private _employee: Employee;

@Input()
set employee(val: Employee) {
  console.log('employee changed from ' + JSON.stringify(this._employee)
    + ' to ' + JSON.stringify(val));
  this._employee = val;
}
get employee(): Employee {
  return this._employee;
}

ngOnChanges
  • We get all the changes instead of just the changes related to a single property
  • Useful when multiple properties change
Property Setter
  • Property setter is specific to a given property, so we only get changes of that specific property
  • Useful when you want to keep track of a single property
Video Link


Angular component communication

Suggested Videos
Part 34 - Angular component input property change detection | Text | Slides
Part 35 - Angular input change detection using property setter | Text | Slides
Part 36 - Angular property setter vs ngonchanges | Text | Slides

In this video we will discuss, how to pass data from child component to parent component.



Component Input Property
  • In Part 33 of Angular CRUD tutorial we discussed how to pass data from parent component to child component.
  • To pass data from parent component to child component we use input properties.
  • In the child component we create a property with @Input decorator. 
  • The parent component then binds to the child component's input property.

Component Output Property
  • On the other hand, to pass data from child component to parent component we use output properties.
  • The child component raises an event to pass data to the parent component. 
  • To create and raise an event, we use EventEmitter object.
  • So the output property is an event defined using EventEmitter object and decorated with @Output decorator.
  • To specify the type of data that we want to pass from the child component to parent component we use the EventEmitter generic argument.
In the example below, the notify event is used to pass string data from the child component to parent component. This event data is commonly called event payload.
@Output() notify: EventEmitter<string> = new EventEmitter<string>();

If you want to pass a number instead of a string as event data, then you specify the generic argument type as number instead of string.
@Output() notify: EventEmitter<number> = new EventEmitter<number>();

If you want to be able to pass any type of data, you can use 'any' as the generic argument type.
@Output() notify: EventEmitter<any> = new EventEmitter<any>();

You can only pass one value using EventEmitter. If you want to pass more than one value using EventEmitter use a custom type like Employee as the generic argument.
@Output() notify: EventEmitter<Employee> = new EventEmitter<Employee>();

We want the "notify" custom event to be raised when we click on any of the "Employee" panel shown below.
passing data from nested component in angular

The child component DisplayEmployeeComponent is responsible for displaying Employee details in a Bootstrap Panel. In (display-employee.component.html) file, wire up the click event handler on the <div> element that has Bootstrap panel css classes panel and panel-primary.
<div class="panel panel-primary" (click)="handleClick()">

To raise the custom event, use the emit() method of the EventEmitter object. The event payload is passed as the argument to the emit() method. So in display-employee.component.ts file include handleClick() method as shown below.

handleClick() {
  this.notify.emit(this.employee);
}

Here is the complete code in display-employee.component.ts file

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Employee } from '../models/employee.model';

@Component({
  selector: 'app-display-employee',
  templateUrl: './display-employee.component.html',
  styleUrls: ['./display-employee.component.css']
})
export class DisplayEmployeeComponent implements OnInit {
  @Input() employee: Employee;
  @Output() notify: EventEmitter<Employee> = new EventEmitter<Employee>();

  constructor() { }

  ngOnInit() {
  }

  handleClick() {
    this.notify.emit(this.employee);
  }
}

Now, in the parent component (list-employees.component.html) bind to the custom event raised by the child component. Notice we are using event binding to bind to the notify event. We are handling the notify event in the parent component using handleNotify($event) method. $event is the data from the child component.

<h1 *ngIf="dataFromChild">
    {{ dataFromChild?.name + ' ' + dataFromChild?.gender }}
</h1>
<div *ngFor="let employee of employees">
    <app-display-employee [employee]="employee"
                          (notify)="handleNotify($event)">
    </app-display-employee>
</div>

In list-employees.component.ts file, include handleNotify() method as shown below. This event handler method assigns the event data received from the child component to dataFromChild property. The view template (list-employees.component.html) binds to this dataFromChild property to display the employee name and gender.

handleNotify(eventData: Employee) {
  this.dataFromChild = eventData;
}

Video Link


Call child component methods and properties using template reference variable

Suggested Videos
Part 35 - Angular input change detection using property setter | Text | Slides
Part 36 - Angular property setter vs ngonchanges | Text | Slides
Part 37 - Angular component communication | Text | Slides

In this video we will discuss how to call child component methods and properties from parent component. One way to do this is by using output properties. We discussed output properties in Part 37 of Angular CRUD tutorial. Another way, to pass data from the child component to the parent component is by using a template reference variable.


Let us understand this with an example. We want to do the same thing that we did with Output properties in Part 37. The child component DisplayEmployeeComponent is responsible for displaying each Employee details in a Bootstrap Panel. 

Here is what we want to do. When we click on any of the employee panel we want to display that employee name and gender as shown in the image below. So we need to pass employee name and gender from the child component (DisplayEmployeeComponent) to parent component (ListEmployeesComponent).


angular 5 template reference variable

Here is the child component class. Notice the class has employee property and getNameAndGender() method. We will be calling both of these from the parent component (ListEmployeesComponent) using a template reference variable.

export class DisplayEmployeeComponent {
  @Input() employee: Employee;

  getNameAndGender(): string {
    return this.employee.name + ' ' + this.employee.gender;
  }
}

Code in Parent Component View Template (list-employees.component.html)

<h1 #h1Variable></h1>

<div *ngFor="let employee of employees">
  <div (click)="h1Variable.innerHTML = childComponent.getNameAndGender()">
    <app-employee-display [employee]="employee" #childComponent>
    </app-employee-display>
  </div>
</div>

Code Explanation : 
  • #childComponent is the template reference variable to the child component. Using this template variable we can call child component public property (employee) and method (getNameAndGender())
  • <div (click)="handleClick(childComponent.getNameAndGender())">. Using the template reference variable we are calling the child component method getNameAndGender(). The value this method returns is assigned to the innerHTML property of the <h1> element. #h1Variable is the template reference variable for <h1> element.
At this point when you click on an employee panel, you will see that employee's name and gender displayed by the <h1> element.

Calling the child component property using template reference variable : Notice in the example below, we are calling the child component public property employee using the template reference variable childComponent.

<h1 #h1Variable></h1>

<div *ngFor="let employee of employees">
  <div (click)="h1Variable.innerHTML = childComponent.employee.name + ' ' + childComponent.employee.gender">
    <app-employee-display [employee]="employee" #childComponent>
    </app-employee-display>
  </div>
</div>

Even now, when you click on an employee panel, you will see that employee's name and gender displayed by the <h1> element exactly the same way as before.

Summary : There are 2 ways to pass data from Child Component to Parent Component
  • Output Properties 
  • Template Reference Variable
With Output properties there are several moving parts. In the child component we need to create a custom event. Raise the custom event. From the parent component bind to the child component event and handle it. With the template reference variable approach, we do not have so many moving parts. We just declare a template reference variable and use it to call the child component public properties and methods. 

Video Link


Angular route guards

Suggested Videos
Part 36 - Angular property setter vs ngonchanges | Text | Slides
Part 37 - Angular component communication | Text | Slides
Part 38 - Call child component methods and properties | Text | Slides

In this video we will discuss CanDeactivate route guard in Angular. We will also discuss how to access angular template reference variable in component class.


First let's understand, why route guards are required. Consider the following "Create Employee" data entry form. This is a pretty big form. Let's say you have filled 90% of the form fields and you accidentally clicked on the "List" navigation link. The application immediately redirects you to the "list" route and all your data on the "Create Employee" form is lost. Wouldn't it have been nice if there was an alert asking the user if he really wants to discard his changes and navigate away from the Create Employee form


angular candeactivate example

A routing guard called CanDeactivate can help us achieve this very easily. The following table has the common routing guards and their purpose.

Route Guard Use
CanDeactivate Guard navigation away from the current route
CanActivate Guard navigation to a route
CanActivateChild Guard navigation to a child route
CanLoad Guard navigation to a feature module loaded asynchronously
Resolve Perform route data retrieval before route activation

We will discuss each of these routing guards with an example in our upcoming videos. In this video we will discuss CanDeactivate guard.

There are 3 steps to use a routing guard in Angular.
  • Build the route guard
  • Register the guard with angular dependency injection system
  • Tie the guard to a route 
Building the route guard : A route guard can be implemented as a function or a service. In this video let's create a service. In our upcoming videos we will discuss creating a function.

Create a new file, in the employees folder. Name it create-employee-can-deactivate-gaurd.service.ts. Copy and paste the following code.

import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { CreateEmployeeComponent } from './create-employee.component';

@Injectable()
export class CreateEmployeeCanDeactivateGuardService
    implements CanDeactivate<CreateEmployeeComponent> {

    constructor() { }

    canDeactivate(component: CreateEmployeeComponent): boolean {
        if (component.createEmployeeForm.dirty) {
            return confirm('Are you sure you want to discard your changes?');
        }

        return true;
    }
}

Code Explanation : 
  • Since we are implementing the routing guard as a service, decorate the guard class with @Injectable() decorator.
  • Since we want to implement CanDeactivate routing guard, make the guard class implement CanDeactivate interface.
  • CanDeactivate interface supports generics. In our case, since we are creating a guard for CreateEmployeeComponent, we have specified CreateEmployeeComponent as the argument for the generic type of CanDeactivate interface.
  • CanDeactivate interface has one method called canDeactivate(). Our routing guard class needs to provide implementation for this interface method.
  • canDeactivate() method returns true or false. True to allow navigation away from the route. False to prevent navigation.
  • The first parameter that is passed to the canDeactivate() method is the CreateEmployeeComponent. We are using this parameter to check if the component is dirty. If it is dirty, we are triggering JavaScript confirm dialog to the user.
  • If the component is not dirty we simply return true, to allow navigation away from the "create" route.
How to check if the form is dirty : Include the following line of code in CreateEmployeeComponent class
@ViewChild('employeeForm') public createEmployeeForm: NgForm;

@ViewChild() decorator provides access to the NgForm directive in the component class. employeeForm which is passed as the selector to the @ViewChild() decorator is the form template reference variable. 

The public property "createEmployeeForm" is used to check if the form is dirty.

Register the guard with angular dependency injection system : Since the routing guard is implemented as a service, we need to register it in a module. At the moment we have only one module in our application and that is the root module AppModule. Import and register CreateEmployeeCanDeactivateGuardService in app.module.ts file using the providers property.

@NgModule({
  declarations: […
  ],
  imports: […
  ],
  providers: [CreateEmployeeCanDeactivateGuardService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Tie the guard to a route : Using the route guard, we want to prevent navigating away from the "create" route, so tie the route guard with the "create" route in app.module.ts file as shown below.

const appRoutes: Routes = [
  {
    path: 'list', component: ListEmployeesComponent
  },
  {
    path: 'create',
    component: CreateEmployeeComponent,
    canDeactivate: [CreateEmployeeCanDeactivateGuardService]
  },
  {
    path: '', redirectTo: '/list', pathMatch: 'full'
  }
];

At this point, if you try to navigate away from the "create" route when the form is dirty you get the alert as expected. The browser back and forward buttons also prevent the navigation away from the "create" route.

CanDeactivate limitations : CanDeactivate guard does not prevent route deactivation
  • If you type a different url in the address bar directly OR
  • If you close the tab or the browser window OR
  • If you navigate to an external URL
Video Link


Angular route params

Suggested Videos
Part 37 - Angular component communication | Text | Slides
Part 38 - Call child component methods and properties | Text | Slides
Part 39 - Angular route guards | Text | Slides

In this video we will discuss
  • Creating a route with parameters and
  • Activating the route

Create a route with parameters : To create a route with parameter include a FORWARD SLASH, a COLON and a place holder for the parameter. The example below, creates a route with parameter id.

{ path: 'employees/:id', component: EmployeeDetailsComponent }

You can have more than one parameter in a route. The following route definition creates a route with 2 parameters - id and name.

{ path: 'employees/:id/:name', component: EmployeeDetailsComponent }


Activating the route with parameters : One way to activate the route is by using the routerLink directive.

<a [routerLink]="['employees',2]">
    Get Employee with Id 2
</a>

Code Explanation:
  • Notice in this example we are binding routerLink directive to an array.
  • This array is called link parameters array.
  • The first element in the array is the path of the route to the destination component.
  • The second element in the array is the route parameter, in our case the employee Id.
Another way to activate the route is by using the Angular Router service naviaget() method. Notice to the navigate method also we are passing the same link parameter array.

constructor(private _router: Router) { }

onClick(employeeId: number) {
  this._router.navigate(['/employees', employeeId]);
}

Angular CLI command to generate EmployeeDetailsComponent
ng g c employees/employee-details --no-spec --flat

list-employees.component.css

.pointerCursor {
    cursor: pointer;
}

list-employees.component.ts

import { Component, OnInit } from '@angular/core';
import { Employee } from '../models/employee.model';
import { EmployeeService } from './employee.service';
import { Router } from '@angular/router';

@Component({
  templateUrl: './list-employees.component.html',
  styleUrls: ['./list-employees.component.css']
})
export class ListEmployeesComponent implements OnInit {
  employees: Employee[];
  constructor(private _employeeService: EmployeeService,
    private _router: Router) { }

  ngOnInit() {
    this.employees = this._employeeService.getEmployees();
  }

  onClick(employeeId: number) {
    this._router.navigate(['/employees', employeeId]);
  }
}

list-employees.component.html

<div *ngFor="let employee of employees">
    <div (click)="onClick(employee.id)" class="pointerCursor">
        <app-display-employee [employee]="employee">
        </app-display-employee>
    </div>
</div>

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
import { SelectRequiredValidatorDirective } from './shared/select-required-validator.directive';

import { AppComponent } from './app.component';
import { ListEmployeesComponent } from './employees/list-employees.component';
import { CreateEmployeeComponent } from './employees/create-employee.component';
import { ConfirmEqualValidatorDirective } from './shared/confirm-equal-validator.directive';
import { EmployeeService } from './employees/employee.service';
import { DisplayEmployeeComponent } from './employees/display-employee.component';
import { CreateEmployeeCanDeactivateGuardService } from './employees/create-employee-can-deactivate-guard.service';
import { EmployeeDetailsComponent } from './employees/employee-details.component';

const appRoutes: Routes = [
  { path: 'list', component: ListEmployeesComponent },
  {
    path: 'create',
    component: CreateEmployeeComponent,
    canDeactivate: [CreateEmployeeCanDeactivateGuardService]
  },
  {
    path: 'employees/:id', component: EmployeeDetailsComponent
  },
  { path: '', redirectTo: '/list', pathMatch: 'full' }
];

@NgModule({
  declarations: [
    AppComponent,
    ListEmployeesComponent,
    CreateEmployeeComponent,
    SelectRequiredValidatorDirective,
    ConfirmEqualValidatorDirective,
    DisplayEmployeeComponent,
    EmployeeDetailsComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    BsDatepickerModule.forRoot(),
    RouterModule.forRoot(appRoutes)
  ],
  providers: [EmployeeService, CreateEmployeeCanDeactivateGuardService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Video Link


Angular read route parameters

Suggested Videos
Part 38 - Call child component methods and properties | Text | Slides
Part 39 - Angular route guards | Text | Slides
Part 40 - Angular route params | Text | Slides

In this video we will discuss, reading route parameter values in Angular 2 and later versions.


To read the route parameter value use Angular ActivatedRoute service. 
  • There are 2 ways to read the route parameter value.
  • We can either use the snapshot approach or observable approach.
  • Snapshot approach works fine, if you navigate to another component before navigating from the current employee to the next employee. In our case we are always navigating back to the ListEmployeesComponent before navigating to view another employee details.
  • If you expect users to navigate from employee to employee directly, without navigating to another component first, then you need to use the observable approach. We will discuss the observable approach in our next video.

constructor(private _route: ActivatedRoute) { }

ngOnInit() {
    const id = +this._route.snapshot.params['id'];
}

Since Angular 4, params have been deprecated in favor of the new interface paramMap. So if you are using Angular 4 or above, use paramMap instead of params.

ngOnInit() {
    const id = +this._route.snapshot.paramMap.get('id');
}

Introduce getEmployee() method in employee.service.ts file

getEmployee(id: number): Employee {
    return this.listEmployees.find(e => e.id === id);
}

employee-details.component.html

<div class="panel panel-primary">
  <div class="panel-heading">
    <h3 class="panel-title">{{employee.name}}</h3>
  </div>
  <div class="panel-body">
    <div class="col-xs-10">
      <div class="row vertical-align">
        <div class="col-xs-4">
          <img class="imageClass" [src]="employee.photoPath" />
        </div>
        <div class="col-xs-8">

          <div class="row">
            <div class="col-xs-6">
              Gender
            </div>
            <div class="col-xs-6">
              : {{employee.gender}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Date of Birth
            </div>
            <div class="col-xs-6">
              : {{employee.dateOfBirth | date}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Contact Preference
            </div>
            <div class="col-xs-6">
              : {{employee.contactPreference}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Phone
            </div>
            <div class="col-xs-6">
              : {{employee.phoneNumber}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Email
            </div>
            <div class="col-xs-6">
              : {{employee.email}}
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Department
            </div>
            <div class="col-xs-6" [ngSwitch]="employee.department">
              :
              <span *ngSwitchCase="1">Help Desk</span>
              <span *ngSwitchCase="2">HR</span>
              <span *ngSwitchCase="3">IT</span>
              <span *ngSwitchCase="4">Payroll</span>
              <span *ngSwitchDefault>N/A</span>
            </div>
          </div>
          <div class="row">
            <div class="col-xs-6">
              Is Active
            </div>
            <div class="col-xs-6">
              : {{employee.isActive}}
            </div>
          </div>

        </div>
      </div>
    </div>
  </div>
  <div class="panel-footer">
    <a class="btn btn-primary" routerLink="/list">
      Back to List
    </a>
  </div>
</div>

employee-details.component.ts

import { Component, OnInit } from '@angular/core';
import { Employee } from '../models/employee.model';
import { ActivatedRoute } from '@angular/router';
import { EmployeeService } from './employee.service';

@Component({
  selector: 'app-employee-details',
  templateUrl: './employee-details.component.html',
  styleUrls: ['./employee-details.component.css']
})
export class EmployeeDetailsComponent implements OnInit {
  employee: Employee;
  constructor(private _route: ActivatedRoute,
    private _employeeService: EmployeeService) { }

  ngOnInit() {
    const id = +this._route.snapshot.paramMap.get('id');
    this.employee = this._employeeService.getEmployee(id);
  }
}

employee-details.component.css

.imageClass{
    width:200px;
    height:200px;
}
.vertical-align{
    display: flex;
    align-items: center;
}

Video Link


Subscribe to angular route parameter changes

Suggested Videos
Part 39 - Angular route guards | Text | Slides
Part 40 - Angular route params | Text | Slides
Part 41 - Angular read route parameters | Text | Slides

In this video we will discuss how to subscribe to angular route parameter changes and then execute some code in response to those changes. In our previous video, we discussed there are 2 ways to read the route parameter values. We can either use the snapshot approach or observable approach. We discussed the snapshot approach in our previous video. In this video we will discuss the observable approach.


Snapshot approach works fine, if you navigate to another component before navigating from the current employee to the next employee. In our case we are always navigating back to the ListEmployeesComponent before navigating to view another employee details.


If you expect users to navigate from employee to employee directly, without navigating to another component first, then you need to use the observable approach. Notice, on the EmployeeDetailsComponent we now have "View Next Employee" button.
angular subscribe route change

Here is what we want to do : Every time when we click this "View Next Employee" button, we want to display the next employee details on the page. Notice in this workflow, we are not navigating to another component before navigating from the current employee to the next employee. So the snapshot approach will not work. Let's try to use the snapshot approach and see what happens.

Modify the HTML in employee-details.component.html file to include "View Next Employee" button. Include the HTML for the button, in the panel-footer <div>

<div class="panel-footer">
  <a class="btn btn-primary" routerLink="/list">Back to List</a>
  <button class="btn btn-primary pull-right" (click)="getNextEmployee()">
    View Next Employee
  </button>
</div>

Modify the code in employee-details.component.ts file as shown below

export class EmployeeDetailsComponent implements OnInit {
  employee: Employee;
  // Include a private field _id to keep track of the route parameter value
  private _id;
  constructor(private _route: ActivatedRoute,
    private _employeeService: EmployeeService,
    private _router: Router) { }

  // Extract the route parameter value and retrieve that specific
  // empoyee details using the EmployeeService
    ngOnInit() {
    this._id = +this._route.snapshot.paramMap.get('id');
    this.employee = this._employeeService.getEmployee(this._id);
  }

  // Everytime this method is called the employee id value is
  // incremented by 1 and then redirected to the same route
  // but with a different id parameter value
  getNextEmployee() {
    if (this._id < 3) {
      this._id = this._id + 1;
    } else {
      this._id = 1;
    }

    this._router.navigate(['/employees', this._id]);
  }
}

At this point, run the project and notice that, every time we click "View Next Employee" button the route parameter value changes as expected, but the employee details displayed on the page does not change. This is because the code in ngOnInit() is executed only when the component is first loaded and initialised. 

After that, every time we click "View Next Employee" button, only the route parameter value changes and the component is not reinitialised and hence the code in ngOnInit() is not executed. If you want to react to route parameter changes and execute some code every time the route parameter value changes, then you have to subscribe to the route parameter changes. So modify the code in ngOnInit() method as shown below.

// The paramMap property returns an Observable. So subscribe to it
// if you want to react and execute some piece of code in response
// to the route parameter value changes
ngOnInit() {
  this._route.paramMap.subscribe(params => {
    this._id = +params.get('id');
    this.employee = this._employeeService.getEmployee(this._id);
  });
}

With the above change in place, when we click "View Next Employee" button, the application works as expected.

Please note : paramMap is introduced in Angular 4. So if you are using Angular 4 or any version beyond it, then the above code works. If you are using Angular 2, then use params instead of paramMap as shown below.

ngOnInit() {
  this._route.params.subscribe(params => {
    this._id = +params['id'];
    this.employee = this._employeeService.getEmployee(this._id);
  });
}

Another important point to keep in mind : When we subscribe to an observable in a component, we also must write code to unsubscribe from the observable when the component is destroyed. However, for some observables we do not have to explicitly unsubscribe. The ActivatedRoute observable is one such observable. The angular Router destroys a routed component when it is no longer needed and the injected ActivatedRoute dies with it. 

When to use snapshot over observable while reading route parameter values : Use snapshot approach if the route parameter value does not change and you only want to read the initial route parameter value. On the other hand, if you know the route parameter value changes, and if you want to react and execute some code in response to that change, then use the Observable approach.

Video Link


Angular optional route parameters

Suggested Videos
Part 40 - Angular route params | Text | Slides
Part 41 - Angular read route parameters | Text | Slides
Part 42 - Subscribe to angular route parameter changes | Text | Slides

In this video we will discuss optional route parameters in Angular with a simple example.

On some routes, the route parameters are required and on some routes they are optional. 


For example, when we navigate from Employees list route to employee details route, the employee id is a required route parameter. Without it, we wouldn't know which employee details to retrieve and display.


Let us understand one use case for optional route parameter. If we have just viewed the details of the employee whose ID is 2 and if we navigate back to the employees LIST route, we want to pass the employee ID 2 in the URL as a route parameter to the LIST route, so that specific employee can be styled with a different colour indicating that, we have just viewed his details. 

Notice in the example below, the second employee "Mary" panel is styled with green background colour, indicating that we have just viewed her details.

angular optional route parameters

On the other hand, if we navigate from the CREATE route to the LIST route, we do not have an employee ID to pass to the LIST route. So the ID has to be an optional route parameter on the LIST route. If the employee ID route parameter is present on the LIST route, then that specific employee panel will be styled with a colour different from the rest of the employees in the list. If the ID route parameter is not present, then all the employee panels will have the same colour.

The following route is activated when we navigate from Employee LIST to employee DETAILS. To view a specific employee details, we need his or her ID. Hence in the following route, id is a required route parameter. 

{ path: 'employees/:id', component: EmployeeDetailsComponent }

A required route parameter is part of the route definition and is used in route pattern matching. When defining routes, in the route definition, we include a place holder for required route parameter. In the above route definition, ":id" is the placeholder for employee id required route parameter.

Now if we want to view the details of an employee whose ID is 2, we will navigate to localhost:4200/employees/2

On the other hand, an optional route parameter is not part of the route definition and is not used in route pattern matching. When defining routes, we do not include a place holder for an optional route parameter like we do for the required route parameter. The following is the route for employee LIST.

{ path: 'list', component: ListEmployeesComponent }

When navigating back to the employee LIST from employee DETAILS, we want to pass the ID of the employee whose DETAILS we have just viewed to the LIST route. So the LIST url, looks as shown below. Notice we are passing 2 as the value for id. In this url id is an optional route parameter.

http://localhost:4200/list;id=2

To pass an optional route parameter you use the LINK parameters array as shown below. Notice we are using an object with an optional id parameter. The LIST route works perfectly fine without the id parameter value. If we have the id parameter value, then we style that specific employee with a different colour to indicate he is the employee whose details we have just viewed.

<a class="btn btn-primary" [routerLink]="['/list',{id:employee.id}]">
  Back to List
</a>

Reading optional route parameter is very similar to reading required route parameter. We use the same ActivatedRoute service. 

constructor(private _route: ActivatedRoute) { }

ngOnInit() {
  this.selectedEmployeeId = +this._route.snapshot.paramMap.get('id');
}

In the view template (display-employee.component.html), we want to add panel-success bootstrap css class to the employee panel, if the id of the employee being displayed by that panel IS EQUAL TO the value we have in selectedEmployeeId property.

<div class="panel panel-primary"
     [class.panel-success]="selectedEmployeeId === employee.id">

In our next video, we will discuss the differences between optional route parameters and required route parameters and when to use one over the other.

Video Link


Angular required route parameter vs optional route parameter

Suggested Videos
Part 41 - Angular read route parameters | Text | Slides
Part 42 - Subscribe to angular route parameter changes | Text | Slides
Part 43 - Angular optional route parameters | Text | Slides

In this video we will discuss some of the common differences between required route parameters and optional route parameters in Angular. This is continuation to Part 43. Please watch Part 43 from Angular CURD tutorial.

  • Required route parameters are part of route configuration where as optional route parameters are not.
  • Required route parameters are used in pattern matching i.e when mapping an incoming URL to a named route in our application. Optional route parameters are not used in pattern matching.
  • Optional route parameters must be passed after the required route parameters if any.
  • In general, prefer a required route parameter when the value is simple and mandatory. For example, to view a specific employee details, the ID parameter is mandatory and it is a simple integer. On the other hand, prefer an optional route parameter when the value is optional and complex. For example you want to send many search parameters like NAME, AGE, DEPARTMENT, DOB etc...from the SEARCH PAGE to LIST PAGE.
Video Link


Angular form reset

Suggested Videos
Part 42 - Subscribe to angular route parameter changes | Text | Slides
Part 43 - Angular optional route parameters | Text | Slides
Part 44 - Angular required route parameter vs optional route parameter | Text | Slides

In this video we will discuss, why and how to rest a form in angular.


Sometimes we must reset the form, before we can redirect the user to another route. Let me explain this with an example. 
  1. We have a form to create a new employee
  2. After we fill the form and when we click the "Save" button, the employee data must be saved and the user should be redirected to the "LIST" route.
  3. But canDeactivate guard is added on the "CREATE" route
  4. This means if the form is dirty, the canDecativate guard will prevent us from leaving the "CREATE" route
  5. So there is a need to to RESET the form, which will reset all the form control values to their intial state and also resets the form flags like dirty, pristine, valid, touched etc.
  6. Once the form is REST, the form is no longer dirty, so the canDeactivate guard will not prevent use from leaving the CREATE route

Angular form reset
  • Clears all the form controls 
  • Optionally the form controls can be initialised with default values
  • Resets the form state and individual controls state like dirty, pristine, valid, touched etc.
To RESET the form in HTML
<form #employeeForm="ngForm"
      (ngSubmit)="saveEmployee(employeeForm); employeeForm.reset()">

There are 2 ways to RESET the form in code. One way is to pass the form (NgForm) to the Submit() method and then call reset() method.

saveEmployee(empForm: NgForm): void {
  this._employeeService.save(this.employee);
  empForm.reset();
  this._router.navigate(['list']);
}

The other way is to use the @ViewChild decorator to access form in code and then call reset() method.

@ViewChild('employeeForm') public createEmployeeForm: NgForm;

saveEmployee(): void {
  this._employeeService.save(this.employee);
  this.createEmployeeForm.reset();
  this._router.navigate(['list']);
}

Please note : @ViewChild() decorator provides access to the NgForm directive in the component class. employeeForm which is passed as the selector to the @ViewChild() decorator is the form template reference variable. 

To reset and initialise the form controls with some default values, pass an object to the reset() method with key/value pairs. The key is the form control name and the value is the default value.

this.createEmployeeForm.reset({
  name: 'Test Value',
  email: 'kudvenkat@pragimtech.com'
});

Video Link


Javascript objects and reference variables

Suggested Videos
Part 43 - Angular optional route parameters | Text | Slides
Part 44 - Angular required route parameter vs optional route parameter | Text | Slides
Part 45 - Angular form reset | Text | Slides

This is continuation to Part 45, please watch Part 45 from Angular CRUD tutorial before proceeding.


The following is the reason the submitted data becomes NULL when the angular form is reset
  1. The "Create Employee Form" is bound to the Employee object.
  2. This same employee object is passed to the save method of the Employee Service.
    this._employeeService.save(this.employee);
  3. When the form is reset, the employee object which is bound to the form is also reset. This happens because of the Angular 2 way data-binding.
  4. As the employee object that is bound to the form, and the employee object that is passed to the save() method are the same, when the form is reset, the bound employee object is reset and as a result, the employee object passed to the save() method is also reset.

To solve this create a new employee object and copy over all the values of the employee object, and then pass the newly created employee object to the save() method.

Notice in the example below, we are using Object.assign() method to copy the employee object property values into a new employee object

saveEmployee(): void {
  const newEmployee: Employee = Object.assign({}, this.employee);
  this._employeeService.save(newEmployee);
  this.createEmployeeForm.reset();
  this._router.navigate(['list']);
}

Regarding reference variables the key point to keep in mind is, object reference variables are pointers to objects, they are not objects themselves.

Video Link


Filter pipe in angular

Suggested Videos
Part 44 - Angular required route parameter vs optional route parameter | Text | Slides
Part 45 - Angular form reset | Text | Slides
Part 46 - Javascript objects and reference variables | Text | Slides

In this video we will discuss implementing a filter pipe in Angular. Angular team recommends not to use pipes to filter and sort data. This is because a filtering and sorting pipe can significantly impact the performance of the application if not implemented carefully. To better understand the performance implications, let's implement a custom pipe to filter data. We discussed creating custom pipes in detail in Part 19 of Angular 2 tutorial.


We want to include Search by Name textbox on ListEmployeesComponent
filter pipe in angular


list-employees.component.html

<div class="form-group">
    <input type="text" class="form-control" placeholder="Search By Name"
            style="width:300px" [(ngModel)]="searchTerm" />
</div>
<div *ngFor="let employee of employees | employeeFilter:searchTerm">
    <div (click)="onClick(employee.id)" class="pointerCursor">
        <app-display-employee [employee]="employee" #childComponent>
        </app-display-employee>
    </div>
</div>

In list-employees.component.ts file, include the following searchTerm property

searchTerm: string;

employee-filter.pipe.ts

import { PipeTransform, Pipe } from '@angular/core';
import { Employee } from '../models/employee.model';

@Pipe({
    name: 'employeeFilter'
})
export class EmployeeFilterPipe implements PipeTransform {
    transform(employees: Employee[], searchTerm: string): Employee[] {
        if (!employees || !searchTerm) {
            return employees;
        }

        return employees.filter(employee =>
            employee.name.toLowerCase().indexOf(searchTerm.toLowerCase()) !== -1);
    }
}

Also do not forget to register EmployeeFilterPipe in a module.

As you can see we implemented filtering using a pipe and everything seems to be working fine. So the question that comes to our mind is,

Why did the Angular team recommend not to use pipes to filter and sort data

Well, that's because a filtering and sorting pipe can significantly impact the performance of the application. 

We will discuss these performance implications and the recommended approach to filter and sort data in our next video.

Video Link


Angular pure pipe

Suggested Videos
Part 45 - Angular form reset | Text | Slides
Part 46 - Javascript objects and reference variables | Text | Slides
Part 47 - Filter pipe in angular | Text | Slides

In this video we will discuss
  • What is a pure pipe
  • Why is it not recommended to use pipes to filter and sort data in Angular

This is continuation to Part 47, please watch Part 47 from Angular CRUD tutorial before proceeding.

In Angular, there are two categories of pipes
  • Pure Pipes
  • Impure Pipes

When you create a new pipe, it is pure by default. To make a pipe impure, set it's pure flag to false. Impure pipes can significantly affect the performance of the application. So you have to think very carefully, before you use an impure pipe in your angular application. We will discuss impure pipes and why they are bad from performance perspective in our next video.

@Pipe({
    name: 'employeeFilter',
    pure: false
})
export class EmployeeFilterPipe implements PipeTransform {

Pure pipe
  • Is fast
  • Angular executes a pure pipe only when it detects a pure change to the input value
  • A pure change is either a change to a primitive input value (String, Number, Boolean) or a changed object reference (Array, Date, Object)
  • A pure pipe is not executed if the input to the pipe is an object and only the property values of the object change but not the reference
Why are Pure pipes fast 
  • An input for a pipe can either be a value type (String, Number, Boolean etc) or a reference type (like Array, Date, Object etc.)
  • If the input to the pure pipe is a value type. Since value types store data directly in the memory slot comparing if a value type value has changed is very quick.
  • On the other hand, if the input to the pure pipe is a reference type, it is executed only if the reference of the input object has changed. Checking if an object reference has changed is much faster than checking if each of the object individual property values have changed.
So pure pipes are fast, but using them for filtering data is not a good idea because, the filtering may not work as expected if the source data is updated without a change to the object reference.

One way to make this work is by making the pipe impure. Impure pipes can significantly impact the performance of the application as they run on every change detection cycle.

We will discuss impure pipes and the performance impact they can have in our next video.

Video Link


Angular impure pipe

Suggested Videos
Part 46 - Javascript objects and reference variables | Text | Slides
Part 47 - Filter pipe in angular | Text | Slides
Part 48 - Angular pure pipe | Text | Slides

In this video we will discuss impure pipes and their performance implications.

This is continuation to Part 48, please watch Part 48 from Angular CRUD tutorial before proceeding.


In our previous 2 videos we implemented a pure pipe to filter employee data. A pure pipe is only executed when a pure change to the input value is detected.


Pure pipes are fast, but using them for filtering data is not a good idea because, the filtering may not work as expected if the source data is updated without a change to the object reference.

One way to make this work is by making the pipe impure. Impure pipes can significantly impact the performance of the application as they run on every change detection cycle. To make a pipe impure, set it's pure property to false.

@Pipe({
    name: 'employeeFilter',
    pure: false
})
export class EmployeeFilterPipe implements PipeTransform {

You have to think very carefully when you make a pipe impure. This is because an impure pipe is processed on every change, even when the source data does not change. They run unnecessarily when not required. 

If you have an array with thousands of objects and each object in turn has dozens of properties. Now if we use an impure pipe to filter or sort this array and for some reason on the same page if we are also listening to the mosue move or keystroke event, then the pipe is unnecessarily executed for every mouse move or keystroke which can significantly degrade the performance of the application.

This is the reason, Angular team recommends not to use pipes to filter and sort data. Angular recommends to move the filtering and sorting logic into the component itself. We will discuss how to implement filtering in a component in our next video.

Video Link


Data filter in angular component

Suggested Videos
Part 47 - Filter pipe in angular | Text | Slides
Part 48 - Angular pure pipe | Text | Slides
Part 49 - Angular impure pipe | Text | Slides

In this video we will discuss implementing the data filter logic in an Angular component so we have better control on when that code should and shouldn't execute.


list-employees.component.ts : The code is commented and self-explanatory


export class ListEmployeesComponent implements OnInit {
  employees: Employee[];
  // Use this property to stored filtered employees, so we do not
  // lose the original list and do not have to make a round trip
  // to the web server on every new search
  filteredEmployees: Employee[];

  private _searchTerm: string;

  // We are binding to this property in the view template, so this
  // getter is called when the binding needs to read the value
  get searchTerm(): string {
    return this._searchTerm;
  }

  // This setter is called everytime the value in the search text box changes
  set searchTerm(value: string) {
    this._searchTerm = value;
    this.filteredEmployees = this.filterEmployees(value);
  }

  constructor(private _employeeService: EmployeeService,
    private _router: Router,
    private _route: ActivatedRoute) { }

  ngOnInit() {
    this.employees = this._employeeService.getActiveEmployees();
    this.filteredEmployees = this.employees;
  }

  filterEmployees(searchString: string) {
    return this.employees.filter(employee =>
      employee.name.toLowerCase().indexOf(searchString.toLowerCase()) !== -1);
  }
}

list-employees.component.html : To display the filtered list of employees, in the view template bind to the filteredEmployees property instead of employees property.

<div *ngFor="let employee of filteredEmployees">
    <div (click)="onClick(employee.id)" class="pointerCursor">
        <app-display-employee [employee]="employee" #childComponent>
        </app-display-employee>
    </div>
</div>

Video Link


Angular query params

Suggested Videos
Part 48 - Angular pure pipe | Text | Slides
Part 49 - Angular impure pipe | Text | Slides
Part 50 - Data filter in angular component | Text | Slides

In this video we will discuss Query String Parameters in Angular. Creating and reading Query String Parameters is somewhat similar to creating and reading required and optional route parameters. We discussed required and optional route parameters in Parts 43 and 44 of Angular CRUD tutorial.


Query parameters are usually used when you want the parameters on the route to be optional and when you want to retain those parameters across multiple routes. For example, on the LIST route, you search for a specific employee. You then click on one of the employees in the search results to view that specific employee details on the DETAILS route. At this point, when we navigate back to the LIST route we want to retain the search term used, so we can display the filtered list instead of the full employee list.


Just like optional route parameters, query parameters are not part of the route configuration and therefore they are not used in route pattern matching.

Passing query string parameters in code : We use the second argument of the Router service navigate() method to pass query string parameters.
  • Create an object with queryParams as the key.
  • The value is an object with key/value pairs. 
  • The key is the name of the query parameter and the value is the value for the query parameter.
this._router.navigate(['employees', employeeId], {
  queryParams: { 'searchTerm': this.searchTerm, 'testParam': 'testValue' }
});

The query string parameters start with a question mark and are separated by & as you can see below.
http://localhost:4200/employees/3?searchTerm=John&testParam=testValue

Passing query string parameters in the HTML
<a [routerLink]="['/employees']"
   [queryParams]="{ 'searchTerm': 'john', 'testParam': 'testValue'}">
    List
</a>

Preserve or Merge Query String Parameters : By default, the query string parameters are not preserved or merged when navigating to a different route. To preserve or merge Query Params set queryParamsHandling to either preserve or merge respectively. 

Preserve query string parameters in code
this._router.navigate(['/employees', this._id], {
  queryParamsHandling: 'preserve'
});

Please note : queryParamsHandling is available in Angular 4 and later versions. If you are using Angular 2, you would not have queryParamsHandling. You will have to use preserveQueryParams and set it to true. preserveQueryParams is deprecated since Angular 4.

Merge query string parameters in code :
this._router.navigate(['/employees', this._id], {
  queryParams: { 'newParam': 'newValue' },
  queryParamsHandling: 'merge'
});

Preserve query string parameters in the HTML :
<a [routerLink]="['/list']"
   queryParamsHandling="preserve">
    Back to List
</a>

Merge query string parameters in the HTML :
<a [routerLink]="['/list']"
   [queryParams]="{'newParam': 'newValue'}" queryParamsHandling="merge">
    Back to List
</a>

Next Video : How to read query params.

Video Link


Angular read query string parameters

Suggested Videos
Part 49 - Angular impure pipe | Text | Slides
Part 50 - Data filter in angular component | Text | Slides
Part 51 - Angular query params | Text | Slides

In this video we will discuss, how to read query string parameters in Angular

To read query parameters we use ActivatedRoute service. We use this same service to read required and optional route parameters.


Inject the ActivatedRoute service using the component class constructor
constructor(private _route: ActivatedRoute) { }


Depending on your project requirements, you can then use either the snapshot approach or the observable approach. We discussed the difference between these 2 approaches and when to use one over the other in Part 42 of this Angular CRUD tutorial.

In Angular there are 3 types of parameters.
  • Required parameters
  • Optional parameters
  • Query parameters
When working with any of these parameters, the following properties and methods are very useful.
Member Description
has(name) Returns true if the parameter is present and false if not. Very useful to check for the existence of optional route and query parameters
get(name) Returns the parameter value as a string if present, or null if not present in the map. Returns the first element if the parameter value is an array of values
getAll(name) Returns a string array of the parameter value if found, or an empty array if the parameter is not present in the map. Use getAll when a single parameter could have multiple values
keys Returns a string array of all the parameters in the map

Please note : For required and optional route parameters, we use the paramMap property of the ActivatedRoute object and for Query Parameters, we use queryParamMap property.

Use the snapshot approach if the query params does not change during the lifetime of this component.

if (this._route.snapshot.queryParamMap.has('searchTerm')) {
  this.searchTerm = this._route.snapshot.queryParamMap.get('searchTerm');
} else {
  this.filteredEmployees = this.employees;
}

On the other hand, if you expect the query parameter value to change during the life time of this component, and if you want to react and execute some code in response to that change, then use the Observable approach.

this._route.queryParamMap.subscribe((queryParams) => {
  if (queryParams.has('searchTerm')) {
    this.searchTerm = queryParams.get('searchTerm');
  } else {
    this.filteredEmployees = this.employees;
  }
});

Video Link


Create observable from array

Suggested Videos
Part 50 - Data filter in angular component | Text | Slides
Part 51 - Angular query params | Text | Slides
Part 52 - Angular read query string parameters | Text | Slides

In this video we will discuss, how to create an observable from static data in an array. Along the way, we will discuss, the 2 most common issues that you will run into when working with observables in your angular application.


There are several ways to create an observable. The simplest of all is to use Observable.of() as shown below.


import { Injectable } from '@angular/core';
import { Employee } from '../models/employee.model';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';

@Injectable()
export class EmployeeService {

    private listEmployees: Employee[] = [
        { id: 1, name: 'Mark' },
        { id: 2, name: 'Mary' },
        { id: 3, name: 'John' },
    ];

    getEmployees(): Observable<Employee[]> {
        return Observable.of(this.listEmployees);
    }
}

At this point, you might be wondering why do we have to return an Observable<Employee[]> instead of just an Employee[] from getEmployees() method. Well, this is because in a real world application, we would not have data hard coded like this in the angular service. We retrieve it from a database by calling a server side service using the angular http service. The angular http service returns an observable. 

We discussed Observables and calling server side service using the angular HTTP service in Part 27 of Angular 2 tutorial

In our upcoming videos in this series, we will discuss calling a server side service. So in preparation for that, we are creating and returning an Observable

In a typical real world application, when a server side service is called over HTTP, there may be some latency and we may not get the data immediately. So to simulate some artificial latency and understand the implications it can have on the code that consumes this returned Observable, import and use the delay operator as shown below. Notice we have a delay of 2000 milli-seconds.

import 'rxjs/add/operator/delay';

getEmployees(): Observable<Employee[]> {
    return Observable.of(this.listEmployees).delay(2000);
}

Consider the following code which calls getEmployees() method of EmployeeService. If you are following along with this course, the following code is from ListEmployeesComponent class in list-employees.component.ts. The code is commented and self explanatory.

ngOnInit() {
  this._employeeService.getEmployees().subscribe((empList) => {
    // This code executes asynchronously. When the data is returned
    // after the 2 seconds delay, that's when the employees property is set
    this.employees = empList;
  });

  // This code will not wait for 2 seconds. After a call to the subscribe() method
  // is issued, the application continues to process the below lines of code. So for
  // those 2 seconds this.employees property is undefined, and with in that time, the
  // below code is executed which can have 2 serious implications
  // 1. The list page will not display any data
  // 2. Cannot read property 'length' of undefined error in the console
  this._route.queryParamMap.subscribe(params => {
    if (params.has('searchTerm')) {
      this.searchTerm = params.get('searchTerm');
    } else {
      this.filteredEmployees = this.employees;
      console.log(this.employees.length);
    }
  });
}

To fix these 2 issues, we want the second block of code to execute synchronously after the employees property is populated with data returned from the service. To achieve this move the second block of code, into the callback function passed as a parameter to the subscribe() method.

ngOnInit() {
  this._employeeService.getEmployees().subscribe((empList) => {
    this.employees = empList;
    this._route.queryParamMap.subscribe(params => {
      if (params.has('searchTerm')) {
        this.searchTerm = params.get('searchTerm');
      } else {
        this.filteredEmployees = this.employees;
        console.log(this.employees.length);
      }
    });
  });
}

At this point, when you navigate to the list route, only a part of the page loads first and after 2 seconds when the data becomes available that's when the page is updated with employee list. You don't want to display a partial page to the user, while waiting for the data. We will discuss how to fix this using the resolve guard in our next video.

Video Link


Angular resolve guard

Suggested Videos
Part 51 - Angular query params | Text | Slides
Part 52 - Angular read query string parameters | Text | Slides
Part 53 - Create observable from array | Text | Slides

In this video we will discuss Angular resolve guard with an example. This is continuation to Part 53. Please watch Part 53 from Angular CRUD tutorial before proceeding.


At the moment, when you navigate to the LIST route, only a part of the page loads first and after 2 seconds when the data becomes available that's when the page is updated with employee list. 

You don't want to display a partial page to the user, while waiting for the data. Before we activate the LIST route and display the view template associated with the LIST route, we want to pre-fetch the data. Once the data is available, that's when we want to render the view template, so the end user does not see a partial page. 

So in short, we want to delay rendering the routed component view template until all necessary data have been fetched.


To pre-fetch data for a route we use a route resolver. A route resolver can be implemented as a function or a service. In this video, let's implement the route resolver as a service. In a later video, we will discuss how to implement it as a function.

The following are the steps to implement a route resolve guard

Step 1 : Implement the Route Resolver Service. Add a new file to the "employees" folder. Name it "employee-list-resolver.service.ts". Copy and paste the following code.

import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Employee } from '../models/employee.model';
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import { EmployeeService } from './employee.service';

@Injectable()
// Implement the Resolve interface, as we are implementing a route resolve guard
// Resolve interface supports generics, so specify the type of data that this
// resolver returns using the generic parameter
export class EmployeeListResolverService implements Resolve<Employee[]> {
    // Inject the employeee service as we need it to retrieve employee data
    constructor(private _employeeService: EmployeeService) {
    }
    // Resolve interface contains the following one method for which we need to
    // provide implementation. This method calls EmployeeService & returns employee data
    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Employee[]> {
        return this._employeeService.getEmployees();
    }
}

Step 2 : Register the Route Resolver Service. At the moment we only have one module in our application and that is the root module - AppModule in app.module.ts file.

import { EmployeeListResolverService } from './employees/employee-list-resolver.service';

@NgModule({
  declarations: [...
  ],
  imports: [...
  ],
  providers: [EmployeeListResolverService],
  bootstrap: [AppComponent]
})
export class AppModule {}

Step 3 : Add the Route Resolver Service to the route for which we want to pre-fetch data. In our case we want to add the EmployeeListResolverService on the LIST route. To do this use the resolve property of the route configuration as shown below. Notice, the value for resolve property is an object with a key and a value. The key is employeeList. You can name it anything you want. The value is the resolver service, which provides the employee data. When the angular router sees this configuration, it knows it has to prefect the employee list data, before it can activate the LIST route and display it's associated view template.

const appRoutes: Routes = [
  {
    path: 'list',
    component: ListEmployeesComponent,
    resolve: { employeeList: EmployeeListResolverService }
  },
  // other routes
];

Step 4 : Read the pre-fetched data from the ActivatedRoute. In our case, modify the code in ListEmployeesComponent class to read the data from the route. Since the route resolver service is prefetching the data, we do not need EmployeeService reference in this component anymore. So remove all the EmployeeService references from this component, including the import statement.

export class ListEmployeesComponent implements OnInit {
  // rest of the code
  constructor(private _employeeService: EmployeeService,
    private _router: Router,
    private _route: ActivatedRoute) {

    this.employees = this._route.snapshot.data['employeeList'];

    if (this._route.snapshot.queryParamMap.has('searchTerm')) {
      this.searchTerm = this._route.snapshot.queryParamMap.get('searchTerm');
    } else {
      this.filteredEmployees = this.employees;
    }
  }

  ngOnInit() {
  }
  // rest of the code
}

At this point, when we navigate to the LIST route, the angular router, first pre-fetches the data, before activating the route and rendering it's associated view template. At the moment, while we are waiting for the route resolver to fetch data, the end user does not have any visual clue indicating that the request is being processed. In our upcoming videos we will discuss, how to display loading...icon.

Video Link


Angular router navigation events

Suggested Videos
Part 52 - Angular read query string parameters | Text | Slides
Part 53 - Create observable from array | Text | Slides
Part 54 - Angular resolve guard | Text | Slides

In this video we will discuss the sequence of navigation events that are triggered by the angular router, when navigating from one route to another route. These navigation events range from when the navigation starts and ends to many points in between.


To see these navigation events in action, set enableTracing option to true as shown below. Enabling tracing logs all the router navigation events to the browser console.

RouterModule.forRoot(appRoutes, { enableTracing: true })


The following list shows some of the navigation events
  • NavigationStart
  • NavigationEnd
  • RoutesRecognized
  • GuardsCheckStart
  • GuardsCheckEnd
  • NavigationCancel
  • NavigationError
  • ChildActivationStart
  • ChildActivationEnd
  • ActivationStart
  • ActivationEnd
  • ResolveStart
  • ResolveEnd
What are the use cases of these navigation events
  • Monitor routes 
  • Troubleshoot when routing does not work as expected
  • Display a loading message if there is a delay when navigating from one route to another (We will discuss this in our next video)
Video Link


Angular route loading indicator

Suggested Videos
Part 53 - Create observable from array | Text | Slides
Part 54 - Angular resolve guard | Text | Slides
Part 55 - Angular router navigation events | Text | Slides

In this video we will discuss how to display a loading indicator if there is a delay when navigating from one route to another route in an angular application. This is continuation to Part 55. Please watch Part 55 from Angular CRUD tutorial before proceeding.


At the moment in our application, when we navigate to the LIST route, it will take 2 seconds to pre-fetch data required for the LIST route. This is because, we have a route resolver configured on the LIST route. We implemented this route resolver in Part 54 of Angular CRUD tutorial.


During the 2 seconds wait time, while the route resolve guard is busy retrieving the required data, we want to display a loading indicator, so the user knows the application is busy processing the request and he does not end up clicking on the link multiple times.

angular route loading indicator

To implement the loading indicator, we are going to make use of the Angular Router Navigation events. We discussed these events in our previous video. These navigation events range from when the navigation starts and ends to many points in between. When the navigation starts, we want to show the loading indicator, and when the navigation ends, hide the loading indicator.

To be able to react and execute some code in response to the router navigation events, subscribe to the Angular router events observable.

Step 1 : Modify the code in Root Component (AppComponent) in app.component.ts as shown below.

import { Component, } from '@angular/core';
// Import the Router and navigation events
import {
  Router, NavigationStart, NavigationEnd,
  NavigationCancel, NavigationError, Event
} from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
  // We will use this property to show or hide
  // the loading indicator
  showLoadingIndicator = true;

  // Inject the Angular Router
  constructor(private _router: Router) {
    // Subscribe to the router events observable
    this._router.events.subscribe((routerEvent: Event) => {

      // On NavigationStart, set showLoadingIndicator to ture
      if (routerEvent instanceof NavigationStart) {
        this.showLoadingIndicator = true;
      }

      // On NavigationEnd or NavigationError or NavigationCancel
      // set showLoadingIndicator to false
      if (routerEvent instanceof NavigationEnd ||
        routerEvent instanceof NavigationError ||
        routerEvent instanceof NavigationCancel) {
        this.showLoadingIndicator = false;
      }

    });
  }
}

Step 2 : Bind to the showLoadingIndicator property in the view template of our root component i.e AppComponent in app.component.html file.

<div class="container">
    <nav class="navbar navbar-default">
        <ul class="nav navbar-nav">
            <li>
                <a routerLink="list" queryParamsHandling="preserve">List</a>
            </li>
            <li>
                <a routerLink="create">Create</a>
            </li>
            <li>
                <a [routerLink]="['employees',2]">
                    Get Employee with Id 2
                </a>
            </li>
        </ul>
    </nav>
    <router-outlet>
    </router-outlet>
    <!-- Bind to showLoadingIndicator property in the component class -->
    <div *ngIf="showLoadingIndicator" class="spinner"></div>
</div>

Step 3 : We are using CSS animations to get the effect of a loading spinner. Place the following CSS in app.component.css file

.spinner {
  border: 16px solid silver;
  border-top: 16px solid #337AB7;
  border-radius: 50%;
  width: 80px;
  height: 80px;
  animation: spin 700ms linear infinite;
  top:50%;
  left:50%;
  position: absolute;
}
@keyframes spin {
  0% { transform: rotate(0deg) }
  100% { transform: rotate(-360deg) }
}

The following website has different loading spinners.
https://loading.io/css/

We have to slightly modify some of the CSS properties to be able to use them on our list page. I made the following changes.
  • Removed display property
  • Changed position property value from relative to fixed
  • Add top and left properties and set them to 50%
  • Changed background property value to #337AB7;
With the above changes I have a spinner as shown below.

angular resolve loading indicator

Video Link


Angular canactivate guard example

Suggested Videos
Part 54 - Angular resolve guard | Text | Slides
Part 55 - Angular router navigation events | Text | Slides
Part 56 - Angular route loading indicator | Text | Slides

In this video we will discuss implementing CanActivate guard in Angular with an example.


As the name implies CanActivate guard determines if a route can be activated. There are several use cases for CanActivate guard.
  • We can use it to check if the user is authenticated before allowing him to access protected areas of the application. If he is not authenticated, we redirect him to AccessDenied component or Login component.
  • Similarly we can use it to check, if a specific resource he is looking for exists. if the resource does not exist we redirect him to the PageNotFound component. If the resource exists, we redirect the user to navigate the resource.

In our example, we use a URL as shown below to access a specific employee details. The number 1 in the URL is the employee ID.
http://localhost:4200/employees/1

There is nothing stopping the end user from typing an employee id in the URL that does not exist. So here is what we want to do. 

If the employee with the specified id in the URL exists, then the navigation should be allowed to continue and view that specific employee details. On the other hand, if the employee does not exist, then it should redirect the user to pageNotFound component.

Angular canactivate guard example

Use the following Angular CLI command to generate pageNotFound component. This command also updates the Root module file to import this newly generated component and add it to the declarations array.

ng g c pageNotFound --flat

Include the following <h1> element in page-not-found.component.html file
<h1>The resource you are looking for cannot be found</h1>

Include the following style for <h1> element in page-not-found.component.css file
h1{
    color: red
}

In the root module file, app.module.ts include a route for pageNotFound component.
const appRoutes: Routes = [
  {
    path: 'list',
    component: ListEmployeesComponent,
    resolve: { employeeList: EmployeeListResolverService }
  },
  {
    path: 'create',
    component: CreateEmployeeComponent,
    canDeactivate: [CreateEmployeeCanDeactivateGuardService]
  },
  { path: 'employees/:id', component: EmployeeDetailsComponent },
  { path: '', redirectTo: '/list', pathMatch: 'full' },
  { path: 'notfound', component: PageNotFoundComponent },
];

At this point if you navigate to http://localhost:4200/notfound, you will see pageNotFound component.

Now let's implement CanActivate guard. This guard should check if the employee with the specified id in the URL exists. If the employee does not exist, then it should redirect the user to pageNotFound component. If the employee exists, then it should allow the navigation to continue and view that specific employee details.

Step 1 : Add a new file to the "employees" folder. Name it employee-details-guard.service.ts. Copy and paste the following code.
import {
    CanActivate, Router,
    ActivatedRouteSnapshot,
    RouterStateSnapshot
} from '@angular/router';
import { Injectable } from '@angular/core';
import { EmployeeService } from './employee.service';

@Injectable()
// Make the class implement CanActivate interface as
// we are implementing CanActivate guard service
export class EmployeeDetailsGuardService implements CanActivate {
    constructor(private _employeeService: EmployeeService,
        private _router: Router) { }

    // Provide implementation for canActivate() method of CanActivate interface
    // Return true if navigation is allowed, otherwise false
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
        const employeeExists = !!this._employeeService.getEmployee(+route.paramMap.get('id'));

        if (employeeExists) {
            return true;
        } else {
            this._router.navigate(['/notfound']);
            return false;
        }
    }
}

Step 2 : Register the guard with angular dependency injection system : Since CanActivate guard is implemented as a service, we need to register it in a module. At the moment we have only one module in our application and that is the root module AppModule. Import and register EmployeeDetailsGuardService in app.module.ts file using the providers property. 
import { EmployeeDetailsGuardService } from './employees/employee-details-guard.service';

@NgModule({
  declarations: […
  ],
  imports: […
  ],
  providers: [EmployeeDetailsGuardService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 3 : Tie the guard to a route : We want to guard navigation to employee details, so tie the route guard with the "employees/:id" route in app.module.ts file as shown below. 
const appRoutes: Routes = [
  {
    path: 'list',
    component: ListEmployeesComponent,
    resolve: { employeeList: EmployeeListResolverService }
  },
  {
    path: 'create',
    component: CreateEmployeeComponent,
    canDeactivate: [CreateEmployeeCanDeactivateGuardService]
  },
  {
    path: 'employees/:id',
    component: EmployeeDetailsComponent,
    canActivate: [EmployeeDetailsGuardService]
  },
  { path: '', redirectTo: '/list', pathMatch: 'full' },
  { path: 'notfound', component: PageNotFoundComponent },
];

Video Link


Passing data between components in angular

Suggested Videos
Part 55 - Angular router navigation events | Text | Slides
Part 56 - Angular route loading indicator | Text | Slides
Part 57 - Angular canactivate guard example | Text | Slides

In this video we will discuss different ways of passing data between components.


There are several techniques to pass data between components in angular. We discussed most of these techniques in our previous videos in this series. If the components are nested, then there is a parent child relationship between those components. To pass data from the parent to child component we use input properties. To pass data from the child component to parent component we can either use output properties or template reference variables.


Passing data from Parent Component to Child Component
Input Properties Part 21 - Angular 2 tutorial

Part 33 - Angular CRUD tutorial

Passing data from Child Component to Parent Component
Output Properties Part 22 - Angular 2 tutorial

Part 37 - Angular CRUD tutorial
Template Reference Variables Part 38 - Angular CRUD tutorial

Passing data from Component to Component (No parent child relation)
Angular Service Part 34 - Angular 2 tutorial
Required Route Parameters Part 40 - Angular CRUD tutorial
Optional Route Parameters Part 43 - Angular CRUD tutorial
Query Parameters Part 51 - Angular CRUD tutorial

Let's use some of these techniques to pass data between components. Along the way we will refactor the code in the angular application that we have been working with so far in this video series. 

This will give us little more practice with component communication techniques. We are refactoring code in our application in preparation for performing DELETE and UPDATE operations in our upcoming videos. By the end of this video, our Employee List page should be as shown below.

angular project tutorial

Changes in list-employees.component.html
  • Remove the style property on "Search By Name" text box so the width spans 100%
  • Remove "Change Employee Name" button along with the <div> element that surrounds it
  • Delete changeEmployeeName() method in the component class (list-employees.component.ts)
  • #childComponen template reference variable is not required on <app-display-employee> child componenet. So delete it.
  • Remove the <div> element that surrounds <app-display-employee> child component.
  • Delete "onClick(employee.id)" method in the component class (list-employees.component.ts)
  • Delete (mousemove) event binding and the corresponding method in the component class
  • We want to pass the Search Term we type in the "Search By Name" textbox to the child component DisplayEmployeeComponent. So notice on <app-display-employee> we are binding to searchTerm input property. We do not have this searchTerm input property DisplayEmployeeComponent yet. We will implement that in just a bit.
At this point, the HTML in list-employees.component.html file should be as shown below
<div class="form-group">
    <input type="text" class="form-control"
           placeholder="Search By Name" [(ngModel)]="searchTerm" />
</div>
<div *ngFor="let employee of filteredEmployees">
    <app-display-employee [employee]="employee" [searchTerm]="searchTerm">
    </app-display-employee>
</div>

In list-employees.component.ts file we are not using the Router service anymore. So remove it from the import statement and the constructor. At this point the code in list-employees.component.ts should be as shown below.
import { Component, OnInit } from '@angular/core';
import { Employee } from '../models/employee.model';
import { ActivatedRoute } from '@angular/router';

@Component({
  templateUrl: './list-employees.component.html',
  styleUrls: ['./list-employees.component.css']
})
export class ListEmployeesComponent implements OnInit {
  employees: Employee[];
  filteredEmployees: Employee[];

  private _searchTerm: string;
  get searchTerm(): string {
    return this._searchTerm;
  }
  set searchTerm(value: string) {
    this._searchTerm = value;
    this.filteredEmployees = this.filtereEmployees(value);
  }

  filtereEmployees(searchString: string) {
    return this.employees.filter(employee =>
      employee.name.toLowerCase().indexOf(searchString.toLowerCase()) !== -1);
  }

  constructor(private _route: ActivatedRoute) {

    this.employees = this._route.snapshot.data['employeeList'];

    if (this._route.snapshot.queryParamMap.has('searchTerm')) {
      this.searchTerm = this._route.snapshot.queryParamMap.get('searchTerm');
    } else {
      this.filteredEmployees = this.employees;
    }

  }

  ngOnInit() {
  }
}

Changes in display-employee.component.html file : Include a panel footer. The HTML required for the panel footer is shown below. Paste this HTML just before the last closing </div> element in display-employee.component.html file.
<div class="panel-footer">
  <button class="btn btn-primary" (click)="viewEmployee()">View</button>
  <button class="btn btn-primary">Edit</button>
  <button class="btn btn-danger">Delete</button>
</div>

Changes in display-employee.component.css file : Include the following style for the View, Edit and Delete buttons so all of them have the same width.
button.btn {
    width: 70px;
}

Changes in display-employee.component.ts file : Include searchTerm input properrty. This is the property to which the parent component (ListEmployeesComponent) is binding ans passing the searchTerm we have typed in the "Search By Name" textbox.

Also, include viewEmployee() method. This is the method that is called when "View" button is clicked.
import { Component, OnInit, Input } from '@angular/core';
import { Employee } from '../models/employee.model';
import { ActivatedRoute, Router } from '@angular/router';

@Component({
  selector: 'app-display-employee',
  templateUrl: './display-employee.component.html',
  styleUrls: ['./display-employee.component.css']
})
export class DisplayEmployeeComponent implements OnInit {
  @Input() employee: Employee;
  @Input() searchTerm: string;

  private selectedEmployeeId: number;

  constructor(private _route: ActivatedRoute, private _router: Router) { }

  ngOnInit() {
    this.selectedEmployeeId = +this._route.snapshot.paramMap.get('id');
  }

  viewEmployee() {
    this._router.navigate(['/employees', this.employee.id], {
      queryParams: { 'searchTerm': this.searchTerm }
    });
  }
}

Changes in employee-details.component.html file : Modify "Back to List" button as shown below. Notice we have removed [queryParams] directive. We included this [queryParams] directive to demonstrate merging query parameters. Also set queryParamsHandling to preserve instead of merge.
<a class="btn btn-primary" [routerLink]="['/list',{id:employee.id}]"
   queryParamsHandling="preserve">
    Back to List
</a>

Changes in app.component.html file : In the menu we do not need "Get Employee with Id 2" link. So remove the associated menu item.

In our upcoming videos we will discuss implementing UPDATE and DELETE operations.

Video Link


Edit form in angular

Suggested Videos
Part 56 - Angular route loading indicator | Text | Slides
Part 57 - Angular canactivate guard example | Text | Slides
Part 58 - Passing data between components in angular | Text | Slides

In this video we will discuss editing and updating data in Angular. To set the expectations right, we will be updating data on the client side. We will discuss persisting the data to a database table in our upcoming videos when we implement the server side service.


We are going to modify "Create Employee Form" so it supports both 
  • Creating a new employee
  • Editing and updating an existing employee

Changes in Root Module file (app.module.ts) : Change the path in the following route from "create" to "edit/:id"

Existing Route

{
  path: 'create',
  component: CreateEmployeeComponent,
  canDeactivate: [CreateEmployeeCanDeactivateGuardService]
}

Updated Route to support both creating a new employee and editing an existing employee. If the id route parameter value is 0, then the form will be used to create a new employee. If the id value is not 0, then the form will be used to edit an existing employee.

{
  path: 'edit/:id',
  component: CreateEmployeeComponent,
  canDeactivate: [CreateEmployeeCanDeactivateGuardService]
}

Changes in create-employee.component.html : The value attribute of email and phone radio buttons is set to Email and Phone respectively to match with the employee data. Otherwise when we select to edit an existing employee, his saved contact preference value will not be bound to the correct radio button. The change is bolded and italicized.

<div class="form-group" [class.has-error]="contactPreference.invalid
        && contactPreference.touched">
    <label class="control-label">Contact Preference</label>
    <div class="form-control">
        <label class="radio-inline">
            <input type="radio" required #contactPreference="ngModel"
                   name="contactPreference" value="Email"
                   [(ngModel)]="employee.contactPreference"> Email
        </label>
        <label class="radio-inline">
            <input type="radio" required #contactPreference="ngModel"
                   name="contactPreference" value="Phone"
                   [(ngModel)]="employee.contactPreference"> Phone
        </label>
    </div>
    <span class="help-block" *ngIf="contactPreference.errors?.required
                                        && contactPreference.touched">
        Contact Preference is required
    </span>
</div>

The required attribute value is updated to include capital E in Email for the validation to work correctly.

<div class="form-group" [class.has-error]="email.invalid">
    <label for="email" class="control-label">Email</label>
    <input id="email" [required]="contactPreference.value=='Email'"
           type="text" class="form-control" [(ngModel)]="employee.email"
           #email="ngModel" name="email"
           pattern="^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$">
    <span class="help-block" *ngIf="email.errors?.required">
        Email is required
    </span>
    <span class="help-block" *ngIf="email.errors?.pattern && email.touched">
        Email is Invalid
    </span>
</div>

The required attribute value is updated to include capital P in Phone for the validation to work correctly.

<div class="form-group" [class.has-error]="phoneNumber.invalid">
    <label for="phoneNumber" class="control-label">Phone Number</label>
    <input id="phoneNumber" [required]="contactPreference.value=='Phone'"
           #phoneNumber="ngModel" class="form-control" type="text"
           name="phoneNumber" [(ngModel)]="employee.phoneNumber">
    <span class="help-block" *ngIf="phoneNumber.errors?.required">
        Phone Number is required
    </span>
</div>

The value attribute of male and female radio buttons is set to Male and Female respectively to match with the employee data. Otherwise when we select to edit an existing employee, his saved gender value will not be bound to the correct radio button. The change is bolded and italicized.

<div class="form-group"
    [class.has-error]="gender.invalid && gender.touched">
    <label class="control-label">Gender</label>
    <div class="form-control">
        <label class="radio-inline">
            <input type="radio" name="gender" required #gender="ngModel"
                   value="Male" [(ngModel)]="employee.gender"> Male
        </label>
        <label class="radio-inline">
            <input type="radio" name="gender" required #gender="ngModel"
                   value="Female" [(ngModel)]="employee.gender"> Female
        </label>
    </div>
    <span class="help-block" *ngIf="gender.errors?.required && gender.touched">
        Gender is required
    </span>
</div>

Notice, I have included ngIf to show the "Image Preview" button and the image, only if there is a value in the photoPath field. This avoids unnecessary 404 errors in the browser console.

<div class="form-group">
    <button type="button" (click)="togglePhotPreview()" class="btn btn-primary"
            *ngIf="employee.photoPath !=='' && employee.photoPath !==null">
        {{previewPhoto ? "Hide " : "Show " }} Preview
    </button>
</div>

<div class="form-group">
    <img [src]="employee.photoPath" height="200" width="200"
    *ngIf="previewPhoto && employee.photoPath !=='' && employee.photoPath !==null"/>
</div>

Changes in create-employee.component.ts :  Change ngOnInit() and saveEmployee() employee methods as shown below. Also please do not forget to include the following panelTitle property.

panelTitle: string;

// Subscribe to route parameter changes and react accordingly
ngOnInit() {
  this._route.paramMap.subscribe(parameterMap => {
    const id = +parameterMap.get('id');
    this.getEmployee(id);
  });
}

saveEmployee(empForm: NgForm): void {
  const newEmployee = Object.assign({}, this.employee);
  this._employeeService.save(newEmployee);
  empForm.reset();
  this._router.navigate(['list']);
}

private getEmployee(id: number) {
  // If the id is 0, we want to create a new employeeSo we intialise the employee 
  // property with an Employee object with all properties set to nullThe template 
  // is bound to this employee property so all the form fields are displayed blank, 
  // to enter details of a new employee we want to create
  if (id === 0) {
    this.employee = {
      id: null,
      name: null,
      gender: null,
      contactPreference: null,
      phoneNumber: null,
      email: '',
      dateOfBirth: null,
      department: null,
      isActive: null,
      photoPath: null
    };
    // Resetting the form, resets any previous validation errors
    this.createEmployeeForm.reset();
    this.panelTitle = 'Create Employee';
  } else {
    // If the Id is not 0, then retrieve the respective employee using the employee 
    // service. Copy the values into a new object and assign that object as the value 
    // for the employee property. Otherwise the employee property holds a reference 
    // to the employee object in the array in the EmployeeService. This means any 
    // changes we make on the form are automatically saved, without we explicitly
    // saving by clicking the Save button.
    this.employee = Object.assign({}, this._employeeService.getEmployee(id));
    this.panelTitle = 'Edit Employee';
  }
}

Changes in employee.service.ts : Change save() method as shown below

save(employee: Employee) {
  if (employee.id === null) {
    // reduce() method reduces the array to a single value. This method executes
    // the provided function for each element of the array (from left-to-right)
    // When we implement the server side service to save data to the database
    // table, we do not have to compute the id, as the server will assing it
    const maxId = this.listEmployees.reduce(function (e1, e2) {
      return (e1.id > e2.id) ? e1 : e2;
    }).id;
    employee.id = maxId + 1;

    this.listEmployees.push(employee);
  } else {
    const foundIndex = this.listEmployees.findIndex(e => e.id === employee.id);
    this.listEmployees[foundIndex] = employee;
  }
}

Changes in display-employee.component.html : Bind editEmployee() method to the click event of the "Edit" button

<button class="btn btn-primary" (click)="editEmployee()">Edit</button>

Changes in display-employee.component.ts : Include the following editEmployee() method

editEmployee() {
  this._router.navigate(['/edit', this.employee.id]);
}

Changes in app.component.html : Change the "Create" menu item to point to our new route "edit/0".

<li>
    <a routerLink="edit/0">Create</a>
</li>

Next Video : Delete operation in Angular

Video Link


Angular delete form

Suggested Videos
Part 57 - Angular canactivate guard example | Text | Slides
Part 58 - Passing data between components in angular | Text | Slides
Part 59 - Edit form in angular | Text | Slides

In this video we will discuss performing Delete operation in Angular. To set the expectations right, we will be deleting data on the client side. We will discuss deleting data from a database table in our upcoming videos when we implement the server side service.


So here is what we want to do. When we click the "Delete" button, we want to display a confirmation. Are you sure, you want to delete. If the user clicks "No", the confirmation should disappear without deleting. If the user clicks "Yes", only then the employee record should be deleted.


angular delete form

Changes in employee.service.ts : Include the following deleteEmployee() method. The easiest method to remove an element from an array is by using splice() method.

This method has 2 parameters. The first parameters specifies the zero based index of the element we want to remove from the array. The second parameter specifies the number of elements to remove. In our case, we want to remove just one element, so we specified 1 as the value.


deleteEmployee(id: number) {
  const i = this.listEmployees.findIndex(e => e.id === id);
  if (i !== -1) {
    this.listEmployees.splice(i, 1);
  }
}

Changes in display-employee.component.ts : The changes are commented and self explanatory

import {
  Component, OnInit, Input,
  Output, EventEmitter
} from '@angular/core';
import { Employee } from '../models/employee.model';
import { ActivatedRoute, Router } from '@angular/router';
import { EmployeeService } from './employee.service';

@Component({
  selector: 'app-display-employee',
  templateUrl: './display-employee.component.html',
  styleUrls: ['./display-employee.component.css']
})
export class DisplayEmployeeComponent implements OnInit {
  @Input() employee: Employee;
  @Input() searchTerm: string;
  // This output event will be used to notify parent component i.e
  // ListEmployeesComponent when an employee is deleted. so the 
  // ListEmployeesComponent can delete that respective employee
  // from the filteredEmployees array to which the template is bound
  @Output() notifyDelete: EventEmitter<number> = new EventEmitter<number>();
  // This property is used in the view template to show and hide
  // delete confirmation
  confirmDelete = false;

  private selectedEmployeeId: number;

  constructor(private _route: ActivatedRoute, private _router: Router,
    private _employeeService: EmployeeService) { }

  ngOnInit() {
    this.selectedEmployeeId = +this._route.snapshot.paramMap.get('id');
  }

  viewEmployee() {
    this._router.navigate(['/employees', this.employee.id], {
      queryParams: { 'searchTerm': this.searchTerm }
    });
  }

  editEmployee() {
    this._router.navigate(['/edit', this.employee.id]);
  }

  // Call the EmployeeService delete method and raise notifyDelete event, so 
  // the ListEemployeesComponent can delete the same employee from it's 
  // filtered list array
  deleteEmployee() {
    this._employeeService.deleteEmployee(this.employee.id);
    this.notifyDelete.emit(this.employee.id);
  }
}

Changes in display-employee.component.html : Modify the HTML in panel-footer <div> as shown below.

<div class="panel-footer">
    <button class="btn btn-primary" (click)="viewEmployee()">View</button>
    <button class="btn btn-primary" (click)="editEmployee()">Edit</button>
    <span *ngIf="confirmDelete">
        <span>Are you sure you want to delete ?</span>
        <button class="btn btn-danger" (click)="deleteEmployee()">Yes</button>
        <button class="btn btn-primary" (click)="confirmDelete=false">No</button>
    </span>
    <span *ngIf="!confirmDelete">
        <button class="btn btn-danger" (click)="confirmDelete=true">Delete</button>
    </span>
</div>

Changes in list-employees.component.html : Bind to the child component notifyDelete event.

<div class="form-group">
    <input type="text" class="form-control"
           placeholder="Search By Name" [(ngModel)]="searchTerm" />
</div>
<div *ngFor="let employee of filteredEmployees">
    <app-display-employee [employee]="employee" [searchTerm]="searchTerm"
                          (notifyDelete)="onDeleteNotification($event)">
    </app-display-employee>
</div>

Changes in list-employees.component.ts : Include notifyDelete event handler method (onDeleteNotification) and delete the respective employee from the filteredEmployees array to which the view template is bound.

onDeleteNotification(id: number) {
  const i = this.filteredEmployees.findIndex(e => e.id === id);
  if (i !== -1) {
    this.filteredEmployees.splice(i, 1);
  }
}

Video Link


Angular delete form

Suggested Videos
Part 57 - Angular canactivate guard example | Text | Slides
Part 58 - Passing data between components in angular | Text | Slides
Part 59 - Edit form in angular | Text | Slides

In this video we will discuss performing Delete operation in Angular. To set the expectations right, we will be deleting data on the client side. We will discuss deleting data from a database table in our upcoming videos when we implement the server side service.


So here is what we want to do. When we click the "Delete" button, we want to display a confirmation. Are you sure, you want to delete. If the user clicks "No", the confirmation should disappear without deleting. If the user clicks "Yes", only then the employee record should be deleted.


angular delete form

Changes in employee.service.ts : Include the following deleteEmployee() method. The easiest method to remove an element from an array is by using splice() method.

This method has 2 parameters. The first parameters specifies the zero based index of the element we want to remove from the array. The second parameter specifies the number of elements to remove. In our case, we want to remove just one element, so we specified 1 as the value.


deleteEmployee(id: number) {
  const i = this.listEmployees.findIndex(e => e.id === id);
  if (i !== -1) {
    this.listEmployees.splice(i, 1);
  }
}

Changes in display-employee.component.ts : The changes are commented and self explanatory

import {
  Component, OnInit, Input,
  Output, EventEmitter
} from '@angular/core';
import { Employee } from '../models/employee.model';
import { ActivatedRoute, Router } from '@angular/router';
import { EmployeeService } from './employee.service';

@Component({
  selector: 'app-display-employee',
  templateUrl: './display-employee.component.html',
  styleUrls: ['./display-employee.component.css']
})
export class DisplayEmployeeComponent implements OnInit {
  @Input() employee: Employee;
  @Input() searchTerm: string;
  // This output event will be used to notify parent component i.e
  // ListEmployeesComponent when an employee is deleted. so the 
  // ListEmployeesComponent can delete that respective employee
  // from the filteredEmployees array to which the template is bound
  @Output() notifyDelete: EventEmitter<number> = new EventEmitter<number>();
  // This property is used in the view template to show and hide
  // delete confirmation
  confirmDelete = false;

  private selectedEmployeeId: number;

  constructor(private _route: ActivatedRoute, private _router: Router,
    private _employeeService: EmployeeService) { }

  ngOnInit() {
    this.selectedEmployeeId = +this._route.snapshot.paramMap.get('id');
  }

  viewEmployee() {
    this._router.navigate(['/employees', this.employee.id], {
      queryParams: { 'searchTerm': this.searchTerm }
    });
  }

  editEmployee() {
    this._router.navigate(['/edit', this.employee.id]);
  }

  // Call the EmployeeService delete method and raise notifyDelete event, so 
  // the ListEemployeesComponent can delete the same employee from it's 
  // filtered list array
  deleteEmployee() {
    this._employeeService.deleteEmployee(this.employee.id);
    this.notifyDelete.emit(this.employee.id);
  }
}

Changes in display-employee.component.html : Modify the HTML in panel-footer <div> as shown below.

<div class="panel-footer">
    <button class="btn btn-primary" (click)="viewEmployee()">View</button>
    <button class="btn btn-primary" (click)="editEmployee()">Edit</button>
    <span *ngIf="confirmDelete">
        <span>Are you sure you want to delete ?</span>
        <button class="btn btn-danger" (click)="deleteEmployee()">Yes</button>
        <button class="btn btn-primary" (click)="confirmDelete=false">No</button>
    </span>
    <span *ngIf="!confirmDelete">
        <button class="btn btn-danger" (click)="confirmDelete=true">Delete</button>
    </span>
</div>

Changes in list-employees.component.html : Bind to the child component notifyDelete event.

<div class="form-group">
    <input type="text" class="form-control"
           placeholder="Search By Name" [(ngModel)]="searchTerm" />
</div>
<div *ngFor="let employee of filteredEmployees">
    <app-display-employee [employee]="employee" [searchTerm]="searchTerm"
                          (notifyDelete)="onDeleteNotification($event)">
    </app-display-employee>
</div>

Changes in list-employees.component.ts : Include notifyDelete event handler method (onDeleteNotification) and delete the respective employee from the filteredEmployees array to which the view template is bound.

onDeleteNotification(id: number) {
  const i = this.filteredEmployees.findIndex(e => e.id === id);
  if (i !== -1) {
    this.filteredEmployees.splice(i, 1);
  }
}

Video Link


Angular accordion example

Suggested Videos
Part 58 - Passing data between components in angular | Text | Slides
Part 59 - Edit form in angular | Text | Slides
Part 60 - Angular delete form | Text | Slides

In this video we will discuss 
  • How to implement simple accordion type of functionality in Angular
  • Difference between ngIf directive and hidden property in Angular 2 and later versions

Implementing accordion type of functionality in Angular 2 and later versions : When the panel title is clicked, the panel body and the footer must be collapsed. Clicking on the panel title again, must expand the collapsed panel body and footer.


Angular accordion example

There are several ways to do this. One way is to implement this accordion functionality in the component itself where we need it. For example, in our case the display logic for the employee is present in DisplayEmployeeComponent. So we include accordion functionality also in the DisplayEmployeeComponent. 

The benefit of this approach is, it is very easy to implement. The downside is, we cannot reuse this accordion functionality in another component if we need it there. We have to re-implement this same functionality again in that component. 

In our next video we will discuss how to extract common accordion functionality into a separate component using content projection, so it can be reused anywhere in the application where we need that accordion type of functionality.

In this video let's implement accordion functionality in the DisplayEmployeeComponent itself.

Changes in display-employee.component.ts : Include the following panelExpanded boolean property in the component class. Notice we have initialised it to true, so the employee panel is expanded by default when the page first loads.

panelExpanded = true;

Changes in display-employee.component.css : Include the following "pointerCursor" class to make the cursor, a pointer when hovered over panel title, so the end user knows, it is clickable.

.pointerCursor {
    cursor: pointer;
}

Changes in display-employee.component.html : To show and hide panel body and footer, we are using ngIf structural directive. ngIf removes the element from the DOM completely when the condition is false and adds the element back once the condition becomes true. So every time, we click the panel title, the panel body and footer are either added to the DOM or removed from the DOM depending on whether the condition is true or false. 

<div class="panel panel-primary"
     [class.panel-success]="selectedEmployeeId === employee.id">
    <!-- pointerCursor class changes the cursor style to pointer when hovered over 
          the employee panel title. When clicked on the title, the panelExpanded 
          boolean property is toggled from true to false & vice-versa. We use this 
          property to toggle the visibility of panel body & footer -->
    <div class="panel-heading pointerCursor"
                        (click)="panelExpanded = !panelExpanded">
        <h3 class="panel-title">{{employee.name | uppercase}}</h3>
    </div>
    <!-- Render panel-body <div> only if panelExpanded property is true  -->
    <div class="panel-body" *ngIf="panelExpanded">
        <!-- Rest of the HTML -->
    </div>
    <!-- Render panel-footer <div> only if panelExpanded property is true  -->
    <div class="panel-footer" *ngIf="panelExpanded">
        <!-- Rest of the HTML -->
    </div>
</div>

In our case, the user of the application may toggle the visibility several times. So from a performance standpoint, it is better to show and hide the panel body and footer, rather than removing from the DOM and adding them back again when the condition is true. To show and hide we use the hidden property as shown below.

<div class="panel-body" [hidden]="!panelExpanded">
    <!-- Rest of the HTML -->
</div>
<div class="panel-footer" [hidden]="!panelExpanded">
    <!-- Rest of the HTML -->
</div>

ngIf vs hidden in Angular
  • ngIf adds or removes element from the DOM where as hidden property hides and shows the element by adding and removing display: none style. 
  • If you frequently toggle the visibility of an element, it is better to use hidden property from a performance standpoint
  • If you know you will not need to show an element, then ngIf is better. For example, you are logged in as a NON-Administrator and there is a report component on the page that should be displayed only to the Administrators. Since you are logged in as a NON-Administrator, using ngIf to hide the report component is better from  a performance standpoint. Since ngIf does not add the element to the DOM, it also does not execute the code associated with that report component. If you use hidden property instead, the report component will be constructed, all it's associated code is executed, the component is added to the DOM, and to keep it hidden from the non-administrator it uses display:none style. So in short, if you frequently toggle the visibility of an element, it is better to use hidden property. On the other hand, if you know the element will remain hidden and the user does not have the ability to toggle the visibility, then use ngIf structural directive.
Video Link


Angular content projection

Suggested Videos
Part 59 - Edit form in angular | Text | Slides
Part 60 - Angular delete form | Text | Slides
Part 61 - Angular accordion example | Text | Slides

In this video we will discuss content projection in Angular with an example. This is continuation to Part 61. Please watch Part 61 from Angular CRUD tutorial before proceeding.


Content projection helps us create reusable components. In Angular 1, this is called transclusion. Let us understand content projection, with an example. We want to create a reusable accordion type of control. The panel heading must be clickable, and when clicked the panel body and footer must be collapsed. Clicking on the panel heading again, must expand the collapsed panel body and footer. 


Another important requirement is, this accordion panel must be reusable with any other component in our application. The component that uses this accordion panel component, must be able to specify what content it wants in the accordion panel body and footer.

angular 2 ng-content select multiple

For example, if we use this accordion panel, with a ProductComponent that displays a product, then in the accordion panel body, the ProductComponent may want to project and display product image, price, weight etc. In the footer, the ProductComponent may want to project and display buttons to customise the product or buy. 

In our case we want to use this accordion panel, with DisplayEmployeeComponent. So in the panel body we want to project and display, employee photo, gender, date of birth, email etc. In the footer, we want to project and display buttons to View, Edit and Delete employee as shown below.

angular content projection

So the important question that we need to answer is, how will the components that use this accordion component be able to inject variable content into the acoordion panel body and footer. 
By using <ng-content> tag

As you can see in the image below, you can think of this <ng-content> as a place holder for the variable content. In a bit we will understand, how a component that uses this accordion component can project variable content depending on the requirements of your application. 

angular 2 transclusion example

First, let's create our reusable accordion component. This is a reusable component and can be used by another component in our application. So, let's place this component in the "Shared" folder. Use the following Angular CLI command to create the component.
ng g c shared/accordion --flat

accordion.component.ts : Notice, in the component class we have introduced 3 properties. The code is commented and self-explanatory.

export class AccordionComponent implements OnInit {
  // We use this property to set a different CSS class on the employee
  // panel if we have just viewed his details
  @Input() hasJustViewed: boolean;
  // Sets the panel title, in our case the name of the employee
  @Input() title: string;
  // Controls hiding and showing panel body and footer
  @Input() isHidden = false;

  constructor() { }

  ngOnInit() {
  }
}

accordion.component.css : The "pointerCursor" class makes the cursor a pointer when hovered over panel title, so the end user knows, it is clickable.

.pointerCursor {
    cursor: pointer;
}

accordion.component.html : As you can see, we have defined the shell for the accordion panel i.e accordion panel header, body and footer. We also have encapsulated the logic in this component to show and hide the panel body and footer. But the content that goes in the panel body and footer will be decided by the component that consumes this accordion component. The consuming component will also need to bind and pass data for the 3 input properties (title, isHidden and hasJustViewed).

<!-- Add panel-success class only if hasJustViewed property is true -->
<div class="panel panel-primary" [class.panel-success]="hasJustViewed">
    <!-- pointerCursor class changes the cursor style to pointer when hovered
             over the employee panel title. When clicked on the title, isHidden
             boolean property is toggled from true to false & vice-versa. We use
             this property to toggle the visibility of panel body & footer -->
    <div class="panel-heading pointerCursor" (click)="isHidden = !isHidden">
        <h3 class="panel-title">{{title | uppercase}}</h3>
    </div>
    <div class="panel-body" [hidden]="isHidden">
        <!-- ng-content specifies the slot into which the content will be projected
               by the component that consumes this accordion component -->
        <ng-content select=".myPanelBody"></ng-content>
    </div>
    <div class="panel-footer" [hidden]="isHidden">
        <!-- Another slot into which the content can be projected. Since we have more
               than one slot into which the content can be projected, this is called
               multi-slot content projection-->
        <ng-content select=".myPanelFooter"></ng-content>
    </div>
</div>

Changes in display-employee.component.html : The changes are commented and self-explanatory.

<!-- Pass employee name as the value for title input property. Also set
     isHidden input propety to false if you want the panel body and footer
     to be collapsed on the initial page load.-->
<app-accordion [title]="employee.name" [isHidden]="true"
[hasJustViewed]="selectedEmployeeId === employee.id">
<!-- Notice myPanelBody css class is present on this <div>. This CCS class is
used as the selector on the <ng-content> tag in accordion component. So all this
content in this DIV will be projected at the location where we have <ng-content>
tag with css class selector .myPanelBody -->
<div class="col-xs-10 myPanelBody">
  <div class="row vertical-align">
    <div class="col-xs-4">
      <img class="imageClass" [src]="employee.photoPath" />
    </div>
    <div class="col-xs-8">

      <div class="row">
        <div class="col-xs-6">
          Gender
        </div>
        <div class="col-xs-6">
          : {{employee.gender}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Date of Birth
        </div>
        <div class="col-xs-6">
          : {{employee.dateOfBirth | date}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Contact Preference
        </div>
        <div class="col-xs-6">
          : {{employee.contactPreference}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Phone
        </div>
        <div class="col-xs-6">
          : {{employee.phoneNumber}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Email
        </div>
        <div class="col-xs-6">
          : {{employee.email}}
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Department
        </div>
        <div class="col-xs-6" [ngSwitch]="employee.department">
          :
          <span *ngSwitchCase="1">Help Desk</span>
          <span *ngSwitchCase="2">HR</span>
          <span *ngSwitchCase="3">IT</span>
          <span *ngSwitchCase="4">Payroll</span>
          <span *ngSwitchDefault>N/A</span>
        </div>
      </div>
      <div class="row">
        <div class="col-xs-6">
          Is Active
        </div>
        <div class="col-xs-6">
          : {{employee.isActive}}
        </div>
      </div>

    </div>
  </div>
</div>
<!-- The content in the following DIV will be projected at the location
where we have <ng-content> tag with css selector .myPanelFooter -->
<div class="myPanelFooter">
  <button class="btn btn-primary" (click)="viewEmployee()">View</button>
  <button class="btn btn-primary" (click)="editEmployee()">Edit</button>
  <span *ngIf="confirmDelete">
    <span>Are you sure you want to delete ?</span>
    <button class="btn btn-danger" (click)="deleteEmployee()">Yes</button>
    <button class="btn btn-primary" (click)="confirmDelete=false">No</button>
  </span>
  <span *ngIf="!confirmDelete">
    <button class="btn btn-danger" (click)="confirmDelete=true">Delete</button>
  </span>
</div>
</app-accordion>

At the moment we are using class selector to match the projection content with the ng-content slot. We can use any of the CSS selectors (class selector, element selector, attribute selector etc)

Video Link


Online fake REST API

Suggested Videos
Part 60 - Angular delete form | Text | Slides
Part 61 - Angular accordion example | Text | Slides
Part 62 - Angular content projection | Text | Slides

In this video we will discuss creating a fake online REST API

What is REST API
REST stands for Representational State Transfer. REST is an architectural pattern for creating an API that uses HTTP as its underlying communication method. 


The REST architectural pattern specifies a set of constraints that a system should adhere to. Some of these constraints are Client Server constraint, Stateless constraint, Cacheable constraint, Uniform Interface constraint etc. We discussed these constraints in Part 1 of ASP.NET Web API tutorial. Let's quickly recap the Uniform Interface constraint.


Uniform Interface - The uniform interface constraint defines the interface between the client and the server. To understand the uniform interface constraint, we need to understand what a resource is and the HTTP verbs - GET, PUT, POST & DELETE. 

In the context of a REST API, a resource typically represents a data entity like Product, Employee, Customer etc. The HTTP verb (GET, PUT, POST, DELETE) that is sent with each request tells the API what to do with the resource. Each resource is identified by a specific URI (Uniform Resource Identifier) or URL (Uniform Resource Locator). The following table shows some typical requests that you see in an API.

Resource Verb Outcome
/Employees GET Gets list of employees
/Employees/1 GET Gets employee with Id = 1
/Employees POST Creates a new employee
/Employees/1 PUT Updates employee with Id = 1
/Employees/1 DELETE Deletes employee with Id = 1

Depending on the server side technology you use, there are many frameworks that we can use to build a REST API. For example, if your server side technology is Microsoft Dot Net, you can use WCF or ASP.NET Web API to create a REST API. 

Since this is an Angular course, and to stay focused on it, let's create a fake REST API using JSON Server. In our upcoming videos, we will perform all the CRUD operations using this fake REST API.

The following is the JSON Server Github page 
https://github.com/typicode/json-server

Execute the following command to install JSON server
npm install -g json-server

Execute the following command to start the server
json-server --watch db.json

This automatically creates db.json file in the root project folder. Copy and paste the following JSON data in db.json file.

{
  "employees": [
    {
      "id": 1,
      "name": "Mark",
      "gender": "Male",
      "contactPreference": "Email",
      "email": "mark@pragimtech.com",
      "dateOfBirth": "1988/10/25",
      "department": "3",
      "isActive": true,
      "photoPath": "assets/images/mark.png"
    },
    {
      "id": 2,
      "name": "Mary",
      "gender": "Female",
      "contactPreference": "Phone",
      "phoneNumber": 2345978640,
      "dateOfBirth": "1979/11/20",
      "department": "2",
      "isActive": true,
      "photoPath": "assets/images/mary.png"
    },
    {
      "id": 3,
      "name": "John",
      "gender": "Male",
      "contactPreference": "Phone",
      "phoneNumber": 5432978640,
      "dateOfBirth": "1976/3/25",
      "department": "3",
      "isActive": false,
      "photoPath": "assets/images/john.png
    }
  ]
}

At this point, fire up the browser and navigate to http://localhost:3000/employees/ to see the list of all employees. You can test this REST API using a tool like fiddler.

In our upcoming videos we will discuss performing CRUD operation using this fake REST API.

Video Link


Angular client server architecture

Suggested Videos
Part 61 - Angular accordion example | Text | Slides
Part 62 - Angular content projection | Text | Slides
Part 63 - Online fake REST API | Text | Slides

In this video we will discuss how the client communicates with the server in an Angular application. Along the way, we will understand the typical architecture of an angular application. Finally, we will discuss the difference between HTTP POST, PUT and Patch verbs.


angular client server architecture

  • When a browser issues a request, a route in our Angular application responds to that request.
  • There is a component associated with a route and the component code executes. If the component needs data, it calls an angular service.
  • The data access logic is usually encapsulated in an Angular service. If you are wondering, why can't we include the data access logic in the component itself, rather than an Angular service. 
  • Well, that's because, if the data access logic is encapsulated in a service, then the service can be reused across all the components that needs that data access logic.
  • Without the service we would have to repeat the data access code in each component that needs it. Imagine the overhead in terms of time and effort required to develop, debug, test and maintain the duplicated code across multiple places instead of having it in one central place like a service and reusing that service where required. 
  • The Angular service calls the server side service over HTTP. The HTTP verb that is sent with each request to the server, specifies what we want to do with the resource on the server.
  • The server side service talks to the database
HTTP Verb Purpose
GET To get data from the server
POST To post data i.e to create new item on the server
DELETE To delete data
PUT, PATCH To update data

POST PUT
Create a new item Create a new item with a given ID if the item does not exit or update the item with the given ID if the item already exists.
Not Idempotent Idempotent

PUT is idempotent where as POST is not. So what does, Idempotent mean?
Well, since PUT is idempotent, no matter how many times you call it, you would have the same effect. For example, when you use PUT with a specific ID and if a resource with that ID does not exist, PUT creates it. Now if you issue the same PUT request again with the same ID, another item with the same ID will not be created. Instead, that existing item will be updated. So it would not matter how many times you call PUT, it would have the same effect.

Remember we use POST to create a new item. So, when you call POST multiple times, multiple items will be created. So for example, if you have an employee object and when you POST that same employee object 10 times, 10 objects will be created on the server. So POST is not idempotent.

PUT PATCH
Replace an existing Resource entirely i.e update all the properties of a resource Partial update i.e update only a sub-set of the properties of a resource
Updates the item with the given ID if the item already exists or creates a new item with a given ID if the item does not exit An item can only be patched if it exists. We cannot patch an item if it does not exist

Depending on the Angular version being used, we can either user the Angular Http service or HttpClient service to call the server side service.

Angular Version Angular Service to use
Angular Version 4.3.x and later HttpClient
Angular Version < 4.3.x Http

Since Angular Version 4.3.x, the old Http service is deprecated. If you are using a version less than 4.3.x, then your only choice is to use Http service. We discussed using the Http service in Parts 27 and 28 of Angular 2 tutorial. HttpClient service has some great benefits over Http service. We will discuss using the HttpClient service and it's benefits in our upcoming videos in this series.

Summanry
  • When a browser issues a request
  • The request is mapped to route in the Angular application
  • The component that is associated with the route calls the Angular Service
  • The Angular service calls the server side service using HTTP
  • The server side service talks to the database
  • The database provides the data to the server side service
  • The server side service then provides that data to the Angular service on the client side
  • The Angular Service provides the data to the component
  • The component displays the data to the user in the browser
Video Link


Angular httpclient get example

Suggested Videos
Part 62 - Angular content projection | Text | Slides
Part 63 - Online fake REST API | Text | Slides
Part 64 - Angular client server architecture | Text | Slides

In this video we will discuss how to call a server side service using Angular HttpClient service. We will specifically discuss, issuing a GET request to retrieve data from the server.


Step 1 : Import Angular HttpClientModule : Before we can use HttpClient service, we need to import Angular HttpClientModule. In most angular applications we do this in the root module AppModule (app.module.ts)

import { HttpClientModule } from '@angular/common/http';


Include the HttpClientModule in the imports array of @NgModule() decorator of AppModule class

Step 2 : Import and inject HttpClient service : We want to use HttpClient service in our EmployeeService (employee.service.ts)

// Import HttpClient service
import { HttpClient } from '@angular/common/http';

// Inject the service using the service class constructor
@Injectable()
export class EmployeeService {
    constructor(private httpClient: HttpClient) {
    }

    getEmployees(): Observable<Employee[]> {
        return this.httpClient.get<Employee[]>('http://localhost:3000/employees');
    }
}

Notice 
  • We are using the HttpClient service get() method to issue a GET HTTP request. 
  • In addition to get() method, we also have post(), put(), patch(), and delete() methods to perform the respective HTTP operations. 
  • To the get() method we pass the URI of the server side service we want to call. 
  • Also notice we are using the get<T>() method, generic parameter to specify the type of data we are expecting. In our case, we are expecting an Employee[] array back.
  • If we were using the old Http service, we would have to use .json() method on the response to get JSON data back. 
  • With the new HttpClient service, we no longer have to do that. JSON is now the default response. 
Step 3 : Subscribe to the angular observable service : To be able to use getEmployees() method of EmployeeService, we need to subscribe to it as it returns an Observable. If we do not subscribe, the service method will not be called. 

However, there is an exception to this. If the observable service is being consumed by a Resolver, the resolver service will subscribe to the Observable, we do not have to explicitly subscribe. The resolver will automatically subscribe to the observable service. On the other hand, if the getEmployees() method of the EmployeeService is consumed by a Component or another service, then that component or service must explicitly subscribe to the Observable, otherwise it will not be called.

Make sure the JSON server is running. If it is not running the list route does not display anything. Use the following command to start the JSON server
json-server --watch db.json

At the moment, we are not handling errors. What happens if the request fails on the server, or if a poor network connection prevents the request from even reaching the server. In this case, HttpClient service returns an error object instead of a successful response. We will discuss error handling in our next video.

Video Link


Angular httpclient error handling

Suggested Videos
Part 63 - Online fake REST API | Text | Slides
Part 64 - Angular client server architecture | Text | Slides
Part 65 - Angular httpclient get example | Text | Slides

In this video we will discuss error handling in Angular. When using HttpClient, to call a server side service, errors may occur. When they do occur we want to handle these errors. 


When an Angular component needs data, there are usually 3 players
  • The Component itself
  • The Angular Service and
  • The Server Side Service

Angular httpclient error handling

The first question that comes to our mind is, should we handle the service related errors in the service itself or in the component that consumes the service. According to Angular style guide, error inspection, interpretation, and resolution is something you want to do in the service, not in the component.

If all goes well the server side service provides data to the client side angular service and the Angular service provides it to the component, which then displays that data to the user.

However, sometimes the request may fail on the server or on the client. There are two types of errors that can occur. 
  • The server may reject the request, returning an HTTP response with a status code such as 404 or 500. These are error responses.
  • Something could go wrong on the client-side such as a network error that prevents the request from completing successfully or an exception thrown in an RxJS operator. These errors produce JavaScript ErrorEvent objects.
  • The HttpClient captures both kinds of errors in its HttpErrorResponse and you can inspect that response to figure out what really happened.
A typical error handler method may look as shown below.

private handleError(errorResponse: HttpErrorResponse) {
    if (errorResponse.error instanceof ErrorEvent) {
        console.error('Client Side Error :', errorResponse.error.message);
    } else {
        console.error('Server Side Error :', errorResponse);
    }
    // return an observable with a meaningful error message to the end user
    return new ErrorObservable('There is a problem with the service.
           We are notified & working on it. Please try again later.');
}

Please do not forget the following imports

import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
  • So, the important point to keep in mind is, if the HttpErrorResponse is an instance of ErrorEvent, then it means that a client-side or network error occurred. If it's not an instance of ErrorEvent, then it means a server error occurred.
  • In a real world application, we may log the errors to a database table or a file for debugging and fixing.
  • Notice, in the error hanlder, we are logging the actual errors and returning an ErrorObservable with a user-friendly error message.
  • Consumers of the service expect service methods to return an Observable of some kind, even a "bad" one.
  • Displaying the actual raw errors to the end user is bad for two reasons - First they are cryptic and does not make much sense to the end user and second they may contain sensitive information that could be useful for a potential hacker. That is why we are logging the actual error and returning a user friendly error message.
Finally, take the Observables returned by the HttpClient methods and pipe them through to the error handler as shown below.

getEmployees(): Observable<Employee[]> {
  return this.httpClient.get<Employee[]>('http://localhost:3000/employees1')
      .pipe(catchError(this.handleError));
}

Please do not forget the following imports

import { Observable } from 'rxjs/Observable';
import { catchError } from 'rxjs/operators';

With the release of rxjs version 5.5, we have Pipeable Operators that can be used along with the pipe() function. Before the introduction of pipeable operators, we only had chain operators as shown below. The catch operator in the example below is called a patch operator.

import 'rxjs/add/operator/catch';

getEmployees(): Observable<Employee[]> {
    return this.httpClient.get<Employee[]>('http://localhost:3000/employees1')
        .catch(this.handleError);
}

So the point that I am, trying to make is
  • There are 2 types of operators in rxjs - Pipeable Operators and Patch Operators
  • Pipeable Operators are imported from rxjs/operators/
  • Patch Operators are imported from rxjs/add/operator/
  • Pipeable Operators have several benefits over Patch Operators. So if you have rxjs version 5.5 or later use pipeable operators.
  • Use the following link to read the benefits of pipeable operators
    https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
In our case, the angular service getEmployees() method is consumed by a Resolver service, and this resolver service provides the data to the LIST route. If there is an exception, the resolver fails and the target route, in our case the LIST route will not be activated. If a component is directly consuming the angular service getEmployees() method, then it is easy to catch the error observable and display the error message to the user. 

However, when a resolver is involved, the target route is not activated if there is an error. So displaying an error message to the end user is a bit more involved.

In our next video, we will discuss handling errors and displaying error messages when there is a resolver between an angular service and the component.

Video Link


Handling angular resolver errors

Suggested Videos
Part 64 - Angular client server architecture | Text | Slides
Part 65 - Angular httpclient get example | Text | Slides
Part 66 - Angular httpclient error handling | Text | Slides

In this video we will discuss handling errors and displaying meaningful error messages to the user, when there is a resolver in between the Angular component and an Angular Service.


A resolver service is usually used to pre-fetch data for a route, before activating that route. When there is a resolver service, between a component and an angular service and if either the angular service or the resolver service throws an error, that target route will not  be activated at all and you will stay on the current route.


Now if your requirement is to navigate the user to that target route and then display a meaningful error message to the user. The trick to this is to create a custom type which contains 2 things
  • The data that you want to return when there is no error
  • The error message that you want to display to the user if there is an error
As you can see in the custom type below we have 2 public properties
  • employeeList property holds the array of employees
  • error property holds the error message to display if there is an error
  • Notice we have defaulted error to NULL
import { Employee } from '../models/employee.model';

export class ResolvedEmployeeList {
    constructor(public employeeList: Employee[], public error: any = null) { }
}

In the resolver service modify the code as shown below.

import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import { EmployeeService } from './employee.service';
import { ResolvedEmployeeList } from './resolved-employeelist.model';

import { catchError } from 'rxjs/operators/catchError';
import { map } from 'rxjs/operators/map';

@Injectable()
export class EmployeeListResolverService implements Resolve<ResolvedEmployeeList> {
    constructor(private _employeeService: EmployeeService) {
    }

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<ResolvedEmployeeList> {
        return this._employeeService.getEmployees()
            .pipe(
            map((employeeList) => new ResolvedEmployeeList(employeeList)),
            catchError((err: any) => Observable.of(new ResolvedEmployeeList(null, err)))
            );
    }
}

Code explanation :
  • In either cases we are returning our custom type - ResolvedEmployeeList
  • If the resolver completes successfully, we populate the employeeList property of our custom type with the array of employees we get from the service. 
  • If there is an error, we populate the error property of our custom type, and a value of null is pass to the employeeList property.
  • In the target component where this reolver data is consume check if the error property is NULL or NOT and react accordingly.
In list-employees.component.ts file make the following changes

const resolvedEmployeeList: ResolvedEmployeeList
                    = this._route.snapshot.data['employeeList'];

if (resolvedEmployeeList.error == null) {
  this.employees = resolvedEmployeeList.employeeList;
} else {
  this.error = resolvedEmployeeList.error;
}

Code explanation :
  • If resolvedEmployeeList.error si NULL, then we know the service call completed without errors. So we set employees property of the component to the list of employees we have in employeeList property of resolvedEmployeeList object.
  • If resolvedEmployeeList.error is NOT NULL, then we know there is an error.
In the view template, display the error

<div *ngIf="error">
    {{ error }}
</div>

If you do not want to create a separate type just for handling resolver errors, you may modify the code in the Resolver Service as shown below.

@Injectable()
// The resolver returns a union type - either an Employee[] or string
// Employee[]  will be returned if the resolver completes successfully
// else the string error message will be returned
export class EmployeeListResolverService implements Resolve<Employee[] | string> {
    constructor(private _employeeService: EmployeeService) {
    }

    // The return type of the resolve() method matches with the above
    // Resolve interface signtaure
    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Employee[] | string> {
        return this._employeeService.getEmployees()
            .pipe(catchError((err: string) => Observable.of(err)));
    }
}

Modify the code in list-employees.component.ts file as shown below.

// resolvedData can either be a string or Employee[]
const resolvedData: string | Employee[] = this._route.snapshot.data['employeeList'];

// If the resolver completed without errors resolvedData is an Employee[]
if (Array.isArray(resolvedData)) {
  this.employees = resolvedData;
} else {
  this.error = resolvedData;
}

Video Link


Angular httpclient post example

Suggested Videos
Part 65 - Angular httpclient get example | Text | Slides
Part 66 - Angular httpclient error handling | Text | Slides
Part 67 - Handling angular resolver errors | Text | Slides

In this video we will discuss posting data to the server using Angular HttpClient service.


To issue a POST request to the server, we use HttpClient service post() method.


Modify code in save() method in employee.service.ts file as shown below.

save(employee: Employee): Observable<Employee> {
    if (employee.id === null) {
        // const maxId = this.listEmployees.reduce(function (e1, e2) {
        //     return (e1.id > e2.id) ? e1 : e2;
        // }).id;
        // employee.id = maxId + 1;
        // employee.id = 0;

        // this.listEmployees.push(employee);
        return this.httpClient.post<Employee>('http://localhost:3000/employees',
            employee, {
                headers: new HttpHeaders({
                    'Content-Type': 'application/json'
                })
            })
            .pipe(catchError(this.handleError));
    } else {
        const foundIndex =
            this.listEmployees.findIndex(e => e.id === employee.id);

        this.listEmployees[foundIndex] = employee;
    }
}

Code Explanation : 
  • save() method does 2 things. Creates a new employee and updates an existing employee.
  • If the incoming employee object id property is null, then we know it's a new employee 
  • The code to compute employee id is commented. We no longer need to compute the id of the new employee on the client side. The server will do this.
  • We use the post() method of the HttpClient service to issues a POST request to the server.
  • We are using the generic parameter of the post<T> method to specify the type the post() method returns after a successful post. Upon a successful post, the server returns an observable of the same type, in our case an Observable<Employee>
  • The returned Observable will contain the created employee object. This returned object will also have the values for server assigned properties. In our case the id of the employee object is populated by the server.
  • Since the post<Employee>() method returns an Observable<Employee>, we have set the return type of the save() method as such.
Angular HttpClient post parameters : HttpClient post() method has the following 3 parameters

Parameter Purpose
url The URL to which the data must be posted
body The data to post to the server
options Request options if any. On common piece of data that we send to the server using options parameter is the content-type header

Notice, we are using the pipeable operator (catchError) to handle errors. 

Please ignore the code in else block. This block is executed when updating an existing employee. We will discuss updating data using the put() method in our next video.

Modify code in saveEmployee() method in create-employee.component.ts file as shown below.

saveEmployee(empForm: NgForm): void {
  this._employeeService.save(this.employee).subscribe(
    (data: Employee) => {
      // log the employee object after the post is completed
      console.log(data);
      empForm.reset();
      this._router.navigate(['list']);
    },
    (error: any) => { console.log(error); }
  );
}

Next video : Updating data using HttpClient service

Video Link


Angular httpclient put example

Suggested Videos
Part 66 - Angular httpclient error handling | Text | Slides
Part 67 - Handling angular resolver errors | Text | Slides
Part 68 - Angular httpclient post example | Text | Slides

In this video we will discuss updating data on the server using Angular HttpClient service.


We update data by issuing a PUT request. To issue a PUT request, we use HttpClient service put() method.


In employee.service.ts file, include the following updateEmployee() method
baseUrl = 'http://localhost:3000/employees';

// When an update is peformed our server side service does not return anything
// So we have set the return type to void.
updateEmployee(employee: Employee): Observable<void> {
    // We are using the put() method to issue a PUT request
    // We are using template literal syntax to build the url to which
    // the request must be issued. To the base URL we are appending
    // id of the employee we want to update. In addition to the URL,
    // we also pass the updated employee object, and Content-Type header
    // as parameters to the PUT method
    return this.httpClient.put<void>(`${this.baseUrl}/${employee.id}`, employee, {
        headers: new HttpHeaders({
            'Content-Type': 'application/json'
        })
    })
    .pipe(catchError(this.handleError));
}

Please note: When an item is updated, by default we get the http status code 204 no content

Method to get an employee by id
getEmployee(id: number): Observable<Employee> {
    return this.httpClient.get<Employee>(`${this.baseUrl}/${id}`)
        .pipe(catchError(this.handleError));
}

Method to add a new employee
addEmployee(employee: Employee): Observable<Employee> {
    return this.httpClient.post<Employee>(this.baseUrl, employee, {
        headers: new HttpHeaders({
            'Content-Type': 'application/json'
        })
    })
    .pipe(catchError(this.handleError));
}

Modify canActivate() method in employee-details-guard.service.ts file as shown below.
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
    : Observable<boolean> {
    return this._employeeService.getEmployee(+route.paramMap.get('id'))
        .pipe(
            map(employee => {
                const employeeExists = !!employee;

                if (employeeExists) {
                    return true;
                } else {
                    this._router.navigate(['notfound']);
                    return false;
                }
            }),
            catchError((err) => {
                console.log(err);
                return Observable.of(false);
            })
        );
}

Modify code in saveEmployee() method in create-employee.component.ts file as shown below.
saveEmployee(empForm: NgForm): void {
  if (this.employee.id == null) {
    console.log(this.employee);
    this._employeeService.addEmployee(this.employee).subscribe(
      (data: Employee) => {
        console.log(data);
        empForm.reset();
        this._router.navigate(['list']);
      },
      (error: any) => { console.log(error); }
    );
  } else {
    this._employeeService.updateEmployee(this.employee).subscribe(
      () => {
        empForm.reset();
        this._router.navigate(['list']);
      },
      (error: any) => { console.log(error); }
    );
  }
}

Also modify code in getEmployee() method in create-employee.component.ts file to subscribe to the employee service
private getEmployee(id: number) {
  if (id === 0) {
    this.employee = {
      id: null, name: null, gender: null, contactPreference: null,
      phoneNumber: null, email: '', dateOfBirth: null, department: null,
      isActive: null, photoPath: null
    };
    this.createEmployeeForm.reset();
    this.panelTitle = 'Create Employee';
  } else {
    this._employeeService.getEmployee(id).subscribe(
      (employee) => { this.employee = employee; },
      (err: any) => console.log(err)
    );
    this.panelTitle = 'Edit Employee';
  }
}

Modify ngOnInit() method in employee-details.component.ts
ngOnInit() {
  this._route.paramMap.subscribe(params => {
    this._id = +params.get('id');
    this._employeeService.getEmployee(this._id).subscribe(
      (employee) => this.employee = employee,
      (err: any) => console.log(err)
    );
  });
}

On the edit page you may get the following error. We get this error because the template is trying to bind to the name property before the server has returned the data, and the employee object is initialised. So that is the reason we cannot read name property from an undefined employee object.
Cannot read property 'name' of undefined

To fix this error, use the following *ngIf directive in create-employee.component.html file.. Now <div> element and it's children will be rendered only after the employee object is initialized.
<div class="panel panel-primary" *ngIf="employee">

Do the same thing in employee-details.component.html file.

Video Link


Angular httpclient delete example

Suggested Videos
Part 67 - Handling angular resolver errors | Text | Slides
Part 68 - Angular httpclient post example | Text | Slides
Part 69 - Angular httpclient put example | Text | Slides

In this video we will discuss deleting data on the server using Angular HttpClient service.


To issue a DELETE request, we use HttpClient service delete() method.


In employee.service.ts file, include the following deleteEmployee() method

baseUrl = 'http://localhost:3000/employees';

deleteEmployee(id: number): Observable<void> {
    return this.httpClient.delete<void>(`${this.baseUrl}/${id}`)
        .pipe(catchError(this.handleError));
}

Code Explanation:
  • deleteEmployee() method takes the ID of the employee to delete as a parameter
  • delete() method does not return anything so we have set the return type to void
  • The URL that is passed as a parameter to the HttpClient delete() method has the ID of the employee to delete
Delete button click event handler is in DisplayEmployeeComponent. So modify deleteEmployee() method in display-employee.component.ts file as shown below.

deleteEmployee() {
  this._employeeService.deleteEmployee(this.employee.id).subscribe(
    () => console.log(`Employee with ID = ${this.employee.id} Deleted`),
    (err) => console.log(err)
  );
  this.notifyDelete.emit(this.employee.id);
}

The success callback function logs the ID of the deleted employee to the console and the error callback function logs the error to the console.

Video Link


Angular CRUD course wrap up and what's next

Suggested Videos
Part 68 - Angular httpclient post example | Text | Slides
Part 69 - Angular httpclient put example | Text | Slides
Part 70 - Angular httpclient delete example | Text | Slides

This is Part 71 and the final video of this Angular CRUD course

We have covered a lot of ground in this course. We have learnt many angular concepts that we were not able to cover in Angular 2 course. Including this video, there are 71 Videos and the duration is around 12 hours.



I hope you have enjoyed this course as much as I did creating it. We have used Angular version 5 in this course.



Resources you need for this course

Download the complete project source code

Instructions to run the AngularCrud project

Angular CRUD playlist

Angular CRUD - Text Articles and Slides

Download videos and slides for offline viewing

As there are different versions of Angular, a common question that I keep getting is - Which version should I use to start learning Angular

The first version of Angular is officially called AngularJS. However, some people call it Angular 1 or Angular JS 1, but it's officially called AngularJS. Starting from version 2, it is called just Angular and not AngularJS. The latest version as of this recording is Angular 6. So the following are the different Angular versions.
  • AngularJS
  • Angular 2
  • Angular 4
  • Angular 5
  • Angular 6
To understand the differences between these versions and why Angular 3 is skipped please check out the following video.
https://www.youtube.com/watch?v=bAx2LgQLkl8

There is a massive difference between AngularJS and the rest of the Angular versions (i.e Angular 2, 4, 5, & 6)

However, there is no much difference between Angular 2, Angular 4, Angular 5 and Angular 6. The way we build angular applications using Angular 2, 4, 5 or 6 is very identical. We use the same approach and programming constructs.

As part of your job, If you know you will be working on and supporting an application that was built using the initial AngularJS version, then I suggest learn AngularJS
https://www.youtube.com/playlist?list=PL6n9fhu94yhWKHkcL7RJmmXyxkuFB3KSl

Otherwise, start with Angular 2. Here is the link to Angular 2 playlist. This course duration is 7.5 hours and covers all the basic concepts of Angular.
https://www.youtube.com/playlist?list=PL6n9fhu94yhWqGD8BuKuX-VTKqlNBj-m6

I believe Angular CLI is a great tool to increase your productivity. So I suggest learn Angular CLI as well.
https://www.youtube.com/playlist?list=PL6n9fhu94yhWUcq5Pc16uf8YKXoZ87Vh_

Once you are comfortable with the concepts discussed in Angular 2 course and Angular CLI. Start with Angular CRUD tutorial at the following link. 
https://www.youtube.com/playlist?list=PL6n9fhu94yhXwcl3a6rIfAI7QmGYIkfK5

In this Angular CRUD course we are using Angular 5. Though this course uses Angular 5, we still build angular applications the same way ,as we have built them using Angular 2. The newer Angular versions have some new features introduced. In this Angular CRUD course we will discuss all those angular concepts we were not able to cover in Angular 2 course. Hope you will find these resources useful to start learning Angular.

What's Next ?
We will start a new angular course and in the project that we will build as part of this new course, we will use the latest version of Angular which as of this recording is Angular 6. In this new course we will cover all those angular concepts we were not able to cover in Angular 2 and Angular CRUD courses. Some of the concepts that we will discuss in this new Angular course are below
  • Reactive Forms
  • Authentication and Authorization
  • HTTP Interceptors
  • Angular Unit Testing
  • Lazy loading modules etc.
If you have a concept in mind that you want us to include in this new course, please leave it as a comment on this video. We will do our best to have it included in this course.

If you find our courses useful, it would be a great help and honour, if you can share these free resources with your friends and family who could benefit as well.

Video Link

Block-3




Creating angular 6 project

Suggested Courses
Angular 2 | Text articles & Slides
Angular CRUD | Text articles & Slides
Angular CLI | Text articles & Slides

This is Part 1 of Angular 6 Tutorial for beginners. In this video
  • We will set up the development environment by installing the tools required for Angular 6 development
  • Create a brand new Angular 6 project using Angular CLI

Pre-requisites
Basic knowledge of Angular and Angular CLI


If you are new to Angular, please check out our 
Angular 2 course and Angular CRUD course

If you are new to Angular CLI, please check out our 
Angular CLI course

Setting up Angular 6 Development environment

Step 1 : Install Node and NPM using the link below. 
https://nodejs.org/en/download/

You need Node version 8.x or greater and NPM version 5.x or greater. To veriify the version of NODE and NPM you have, execute the following 2 commands using the command prompt window. Make sure you are running the command prompt as an administrator.
node -v
npm -v

If you already have NODE and NPM installed and if you want to upgrade to the latest version simply download and run the installer again, and it will automatically update NODE and NPM to the latest version.

Step 2 : Install Angular CLI. It is a command line tool that help us create angular applications quickly and easily while still following angular's best practices and conventions. It's a great tool to increase your productivity as an angular developer.

If you do not have Angular CLI installed already, execute the following command and it will install the latest version.
npm install -g @angular/cli

If you already have Angular CLI installed, and you want to upgrade to the latest version, then execute the following command
npm install -g @angular/cli@latest

Step 3 : Download and install Visual Studio Code
https://code.visualstudio.com/download

Create a new Angular 6 project using the Angular CLI : 

Step 1 : Run the command prompt window as an administrator

Step 2 : Execute the following command to create a new Angular 6 project.
ng new Angular6Project -d

Command Explanation
ng Is the Angular CLI
new For generating a new project
Angular6Project Is the name of the project
-d This is dry-run flag. This flag instructs Angular CLI just to list the files it's going to create. It does not actually create them. This is a great option, because it lets us see what files will be generated without actually generating them.

In our case, we do not want test files to be generated so let's also use --skip-tests option to skip generating test files. The following generates a new Angular 6 project and all the required files. Notice, we have not used -d option, so Angular CLI will create the Angular project and all the required files.
ng new Angular6Project --skip-tests

Running the Angular 6 Project

Step 1 : In the command prompt window, use the following command to go to the project directory
cd Angular6Project

Step 2 : Execute the following command to run the Angular 6 project. This command builds, launches your default browser and serves the application using the default port number 4200 (http://localhost:4200/)
ng serve --open (short cut command : ng s -o)

At this point you will see the following on the browser
Welcome to Angular6Project!

This message is coming from the root component AppComponent.

The project structure and the files in angular project have not changed much between Angular 5 and Angular 6. One change I can point out at this time is the Angular CLI configuration file. Prior to Angular 6, the Angular CLI configuration file is called angular-cli.json. In Angular 6, it is renamed to just angular.json. It's not a simple rename, the file format is also slightly different.

In the generated project there are several files and folders. If you are new to these files and folders, please check out Parts 7 and 8 from Angular CLI tutorial

The src folder contains the angular application components, templates, services, styles, images, and anything else the application needs. The files outside of this folder are meant to support building, testing, maintaining, documenting, and deploying the angular application.

To confirm this Angular application is using Angular Version 6, open package.json file and notice all the Angular packages version is 6.1.0.

Video Link


Install Bootstrap for Angular 6

Suggested Videos
Part 1 - Creating angular 6 project | Text | Slides

In this video we will discuss, installing and configuring Bootstrap for use in an Angular 6 project.


We will be using Bootstrap for styling. Install bootstrap using the following NPM command
npm install bootstrap@3 jquery --save


This installs Bootstrap in the node_modules folder. If you do not find the bootstrap folder in node_modules folder, restart visual studio code and you will find it. You can also execute the following command in the integrated terminal window and search for bootstrap folder.
dir node_modules

In Angular CLI configuration file include the path to the Bootstrap CSS file in the styles array. Remember in Angular 6, the Angular CLI configuration file is renamed to angular.json from angular-cli.json.

"styles": [
  "src/styles.css",
  "node_modules/bootstrap/dist/css/bootstrap.min.css"
]

Bootstrap relies on jQuery for some of it's features. If you plan on using those features, please include the path to jQuery and Bootstrap jQuery files in the scripts array in angular.json file.

"scripts": [
  "node_modules/jquery/dist/jquery.min.js",
  "node_modules/bootstrap/dist/js/bootstrap.min.js"
]

To verify that you have the correct paths specified, you can request the respective files by running the angular project and pointing your browser to http://localhost:4200/node_modules/bootstrap/dist/css/bootstrap.min.css

A quick additional test to verify, Bootstrap styles work as expected, include the following button in the root component (app.component.html) file.

<button class="btn btn-primary">
    Bootstrap Styled Button
</button>

Video Link


Angular 6 routing tutorial

Suggested Videos
Part 1 - Creating angular 6 project | Text | Slides
Part 2 - Install Bootstrap for Angular 6 | Text | Slides

In this video we will discuss setting up routing in a separate routing module.


At the moment, in our angular project, we only have one component and that is the root component - AppComponent. Now, let's create the following 2 components, so we can setup routing to navigate between these components.
  • CreateEmployeeComponent
  • ListEmployeesComponent

Use the following 2 Angular CLI commands to create the components.
ng g c employee/create-employee --spec=false --flat=true
ng g c employee/list-employees --spec=false --flat=true


Step 1 : Set <base href="/"> in index.html : When setting up routing in an angular application, the first step is to set the base path using the base href element. The base path tells the angular router, how to compose navigation URLs. When you create a new Angular 6 project, this is included automatically by the Angular CLI. To understand the significance of this base element, please watch Part 4 from Angular CRUD tutorial.

Step 2 : Create a separate routing module : The first question that comes to our mind is - Why should we define routes in a separate routing module.
Well, for separation of concerns and maintainability. If routing is in it's own module, it is easier to find and change routing code if required. 

Now, using the Angular CLI, let's create the routing module. By convention, the routing module class name is called AppRoutingModule and the file is named app-routing.module.ts.
ng generate module app-routing --flat=true --module=app


--module=app tells the Angular CLI to import and register routing module in the application root module AppModule.

The above command can also be written using it's short-hand notation as shown below
ng g m app-routing --flat=true -m=app


Step 3 : Import the Angular RouterModule into the AppRoutingModule and configure the application routes : Here is the modified AppRoutingModule file (app-routing.module.ts). Please note that, the CommonModule is not required in the routing module, so I have deleted it's reference. We generally don't declare components in the routing module so, I also deleted declarations array from @NgModule decorator. The rest of the code is commented and self-explanatory.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

// Import the components so they can be referenced in routes
import { CreateEmployeeComponent } from './employee/create-employee.component';
import { ListEmployeesComponent } from './employee/list-employees.component';

// The last route is the empty path route. This specifies
// the route to redirect to if the client side path is empty.
const appRoutes: Routes = [
  { path: 'list', component: ListEmployeesComponent },
  { path: 'create', component: CreateEmployeeComponent },
  { path: '', redirectTo: '/list', pathMatch: 'full' }
];

// Pass the configured routes to the forRoot() method
// to let the angular router know about our routes
// Export the imported RouterModule so router directives
// are available to the module that imports this AppRoutingModule
@NgModule({
  imports: [ RouterModule.forRoot(appRoutes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule { }

Step 4 : In the application root component file (app.component.html), create the navigation menu and tie the configured routes to it. The directive tells the router where to display routed views.

<div class="container">
    <nav class="navbar navbar-default">
        <ul class="nav navbar-nav">
            <li>
                <a routerLinkActive="active" routerLink="list">List</a>
            </li>
            <li>
                <a routerLinkActive="active" routerLink="create">Create</a>
            </li>
        </ul>
    </nav>
    <router-outlet></router-outlet>
</div>

Next video : Creating a reactive form

Video Link


Angular reactive forms

Suggested Videos
Part 1 - Creating angular 6 project | Text | Slides
Part 2 - Install Bootstrap for Angular 6 | Text | Slides
Part 3 - Angular 6 routing tutorial | Text | Slides


In this video we will discuss Reactive Forms in Angular.

There are 2 ways to create forms in Angular 
  1. Template Driven Forms
  2. Reactive Forms (Also called Model Driven Forms)

As the name implies, Template Driven Forms are heavy on the template meaning we create the form completely in HTML. Template driven forms are easy to build and understand. They are great for creating simple forms. However, creating complex forms using template driven approach is not recommended as the HTML can get very complicated and messy. It is not easy to unit test template forms as the logic is in the HTML.

We discussed template driven forms in Part 5 of Angular CRUD Tutorial

Reactive forms on the other hand allow us to build the form completely in code. This is more flexible and has many benefits over template forms. For example, it is easy to add form input elements dynamically and adjust validation at run-time based on the decisions made in code. It is also easy to unit test as most of the logic and validation is in the component class. The only downside of reactive forms is that they require more code than template forms.

In this video and in our upcoming videos we will discuss everything we need to know to build complex reactive forms.

With a reactive form, we create the entire form control tree in the component class code. Let us understand this by creating a simple form with just 2 form controls as shown below.

angular reactive forms tutorial

Creating a form group model : Two classes that we commonly use to create a form control tree is FormGroup and FormControl. As the names imply to create a form with a group of controls, we create an instance of FormGroup class and to create each input element i.e a form control, we create an instance of FormControl class. So in the CreateEmployeeComponent (create-employee.component.ts) class modify the code as shown below.

import { Component, OnInit } from '@angular/core';
// Import FormGroup and FormControl classes
import { FormGroup, FormControl } from '@angular/forms';

@Component({
  selector: 'app-create-employee',
  templateUrl: './create-employee.component.html',
  styleUrls: ['./create-employee.component.css']
})
export class CreateEmployeeComponent implements OnInit {
  // This FormGroup contains fullName and Email form controls
  employeeForm: FormGroup;

  constructor() { }

  // Initialise the FormGroup with the 2 FormControls we need.
  // ngOnInit ensures the FormGroup and it's form controls are
  // created when the component is initialised
  ngOnInit() {
    this.employeeForm = new FormGroup({
      fullName: new FormControl(),
      email: new FormControl()
    });
  }
}

Right click and go to the definition on FormGroup class constructor. Notice it has 3 parameters.

constructor(controls: { [key: string]: AbstractControl;},
validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null,
asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null);

The first parameter (controls) is required, but the rest of the 2 parameters are optional. As you can see, the controls parameter is used to pass the collection of child controls. In our case we want 2 child controls in the FormGroup - fullName and email. So we pass an object with key/value pairs. The key is the name for the control and the value is an instance of the FormControl class. But, wait a minute, from the intellisense, I see that the value is AbstractControl and not FormControl.

constructor(controls: { [key: string]: AbstractControl;}

So the obvious question that comes to our mind is, how are we able to pass a FormControl instance when it is expecting AbstractControl instance.

Well, FormControl class inherits from AbstractControl class. This allows us to pass FormControl instance as the value. Both FormControl and FormGroup classes inherit from AbstractControl class. This allows us to pass either a FormControl or a FromGroup instance as the value. 

If you are wondering, why do we need to pass a FromGroup instance as the value.

Well, a FormGroup can have a nested FormGroup. We will discuss nested form groups in our upcoming videos.


Binding the FormGroup model and the view : Copy and paste the following HTML in create-employee.component.html file. This is pure HTML. There is no Angular code in this HTML. We have a <form> element and 2 text input elements (for fullName and email)

<form class="form-horizontal">
  <div class="panel panel-primary">
    <div class="panel-heading">
      <h3 class="panel-title">Create Employee</h3>
    </div>
    <div class="panel-body">
      <div class="form-group">
        <label class="col-sm-2 control-label" for="fullName">Full Name</label>
        <div class="col-sm-8">
          <input id="fullName" type="text" class="form-control">
        </div>
      </div>

      <div class="form-group">
        <label class="col-sm-2 control-label" for="email">Email</label>
        <div class="col-sm-8">
          <input id="email" type="text" class="form-control">
        </div>
      </div>

    </div>
    <div class="panel-footer">
      <button class="btn btn-primary" type="submit">Save</button>
    </div>
  </div>
</form>

Now we need to bind the view template to the form group model we created in the component class. For this we make use of the following 2 directives provided by Angular ReactiveFroms module.
  • formGroup
  • formControlName
Here is the modified HTML. Notice the use of formGroup and formControlName directives in the <form> element and the 2 input elements.

<form class="form-horizontal" [formGroup]="employeeForm">
  <div class="panel panel-primary">
    <div class="panel-heading">
      <h3 class="panel-title">Create Employee</h3>
    </div>
    <div class="panel-body">
      <div class="form-group">
        <label class="col-sm-2 control-label" for="fullName">Full Name</label>
        <div class="col-sm-8">
          <input id="fullName" type="text" class="form-control" formControlName="fullName">
        </div>
      </div>

      <div class="form-group">
        <label class="col-sm-2 control-label" for="email">Email</label>
        <div class="col-sm-8">
          <input id="email" type="text" class="form-control" formControlName="email">
        </div>
      </div>

    </div>
    <div class="panel-footer">
      <button class="btn btn-primary" type="submit">Save</button>
    </div>
  </div>
</form>

Please note : 
  • To bind the <form> element to the employeeForm group in the component class we use the formGroup directive. Since "employeeForm" is a property we use square brackets around the formGroup directive to indicate that we are binding to a property.
  • To bind each input element to the associated FormControl in the FormGroup model, we use formControlName directive. Notice we are not using square brackets with formControlName directive. This is because, in this case we are binding to a form control name which is a string and not a property. 
At this point, if you view the page in the browser, you will see the following error in the browser console.
Can't bind to 'formGroup' since it isn't a known property of 'form'

This is because, the 2 directives (formGroup and formControlName) are in ReactiveForms module, but we have not yet imported it in our root module. So in the AppModule (app.module.ts file), import ReactiveFormsModule and include it in the imports array.

import { ReactiveFormsModule } from '@angular/forms';

Accessing form data : To access form data, bind to the ngSubmit event on the <form> element. This ngSubmit event is raised when a button with input type=submit is clicked.

<form class="form-horizontal" [formGroup]="employeeForm"
      (ngSubmit)="onSubmit()">

In the component class (create-employee.component.ts), include onSubmit() method as shown below.

onSubmit(): void {
  console.log(this.employeeForm.value);
}

At this point, fill out the form and click Save button. Notice, the Formgroup value property is logged to the console. The value property of the FormGroup contains each form control name and it's associated value.

At the moment our reactive form is a very simple form with just 2 text box input controls. As we progress through this course will discuss working with checkboxes, radio buttons, dropdownlists etc. We will also discuss form validation, nested form groups, dynamically creating form controls etc.

Video Link


Angular form control and form group

Suggested Videos
Part 2 - Install Bootstrap for Angular 6 | Text | Slides
Part 3 - Angular 6 routing tutorial | Text | Slides
Part 4 - Angular reactive forms tutorial | Text | Slides

In this video we will discuss FormControl and FormGroup classes

  • When working with reactive forms we create instances of FormControl and FormGroup classes to create a form model.
  • To bind an HTML <form> tag in the template to the FromGroup instance in the component class, we use formGroup directive
  • To bind an  HTML <input> element in the template to the FormControl instance in the component class, we use formControlName directive
  • formGroup and formControlName directives are provided by the ReactiveFormsModule
  • Both FormControl and FormGroup classes inherit from AbstractControl base class
  • The AbstractControl class has properties that help us track both FormControl and FormGroup value and state

The following are some of the useful properties provided by the AbstractControl class
  • value
  • errors
  • valid
  • invalid
  • dirty
  • pristine
  • touched
  • untouched
FormControl instance tracks the value and state of the individual html element it is associated with
FormGroup instance tracks the value and state of all the form controls in it's group

To see the form model we created using FormGroup and FormControl classes, log the employeeForm to the console.

onSubmit(): void {
  console.log(this.employeeForm);
}

On Save button click, you should see the following form model in the browser console.

angular form control and form group

To access the FormGroup properties use, employeeForm property in the component class. When you press DOT on the employeeForm property you can see all the available properties and methods.

angular formgroup example

To access a FormControl in a FormGroup, we can use one of the following 2 ways.

employeeForm.controls.fullName.value
employeeForm.get('fullName').value

Note: This same code works, both in the template and component class.

Please include the following HTML, just after the <form> tag, in the template, and you can see the property values change as you interact with the form controls on the form.

<table border="1">
  <tr>
    <th style="padding: 10px">FormGroup</th>
    <th style="padding: 10px">FormControl (fullName)</th>
  </tr>
  <tr>
    <td style="padding: 10px">
      touched : {{ employeeForm.touched }}
      <br/> dirty : {{ employeeForm.dirty }}
      <br/> valid : {{ employeeForm.valid }}
      <br/> Form Values : {{employeeForm.value | json}}
    </td>
    <td style="padding: 10px">
      touched : {{ employeeForm.get('fullName').touched }}
      <br/> dirty : {{ employeeForm.get('fullName').dirty }}
      <br/> valid : {{ employeeForm.get('fullName').valid }}
      <br/> FullName Value : {{employeeForm.get('fullName').value}}
    </td>
  </tr>
</table>

In addition to these properties, AbstractControl also provides the following methods. In our upcoming videos we will use these properties and methods for form validation and working with data.
  • setValidators()
  • clearValidators()
  • updateValueAndValidity()
  • setValue()
  • patchValue()
  • Reset()
Video Link


Angular nested form groups

Suggested Videos
Part 3 - Angular 6 routing tutorial | Text | Slides
Part 4 - Angular reactive forms tutorial | Text | Slides
Part 5 - Angular form control and form group | Text | Slides

In this video we will discuss nested form groups in a reactive form. Along the way, we will also discuss working with radio buttons in a reactive form.


Let's understand, creating nested form groups with an example

angular nested form groups


In addition to fullName and email, we want to add the following 3 fields to "Create Employee" form.
  • Skill Name
  • Experience in Years
  • Proficiency
What we want to be able to ultimately do is add multiple skills dynamically at run time, by clicking "Add a new skill" button.

angular reactive forms nested form groups

When the button is clicked, we want to dynamically add another set of skill related fields i.e 
  • Skill Name
  • Experience in Years and
  • Proficiency
Also, another additional requirement is to keep "Add a new skill" button disabled, until all the skill related fields are properly filled and valid.

So in short, the requirement is to dynamically create a group of form fields and also validate them as a single group so "Add a new skill" button can be enabled or disabled based on the validation state of the group. This can be very easily achieved using a nested form group. So, first let's create a nested form group for skill related fields in the component class.

Step 1: Creating a nested form group in the component class : Form groups can accept both form control and form group instances as children. This allows us to create a nested form group. Modify the code in ngOnInit() life cycle hook as shown below.

ngOnInit() {
  this.employeeForm = new FormGroup({
    fullName: new FormControl(),
    email: new FormControl(),
    // Create skills form group
    skills: new FormGroup({
      skillName: new FormControl(),
      experienceInYears: new FormControl(),
      proficiency: new FormControl()
    })
  });
}

Notice we have created a nested form group with key - skills. This nested form group contains 3 form controls.
  • skillName,
  • experienceInYears and
  • proficiency
Step 2: Grouping the nested form in the template : To group the form elements in the HTML, encapsulate the form elements in a <div> element and use the formGroupName directive on that container <div> element. Bind the formGroupName directive to the skills FormGroup instance in the component class. Bind each input element in the HTML, to the corresponding FormControl instance using the formControlName directive.

<div formGroupName="skills">

  <div class="form-group">
    <label class="col-sm-2 control-label" for="skillName">
      Skill
    </label>
    <div class="col-sm-4">
      <input type="text" class="form-control" id="skillName"
          placeholder="Name" formControlName="skillName">
    </div>
    <div class="col-sm-4">
      <input type="text" placeholder="Experience in Years"
          class="form-control" formControlName="experienceInYears">
    </div>
  </div>

  <div class="form-group">
    <label class="col-md-2 control-label">Proficiency</label>
    <div class="col-md-8">
      <label class="radio-inline">
        <input id="proficiency" type="radio" value="beginner"
               formControlName="proficiency">Beginner
      </label>
      <label class="radio-inline">
        <input id="proficiency" type="radio" value="intermediate"
               formControlName="proficiency">Intermediate
      </label>
      <label class="radio-inline">
        <input id="proficiency" type="radio" value="advanced"
               formControlName="proficiency">Advanced
      </label>
    </div>
  </div>

</div>

At this point, save all the changes and when you fill out the form.

angular access nested formgroup

skills nested formgroup value is reflected on the page. 

get value from nested formgroup

Please note : If you do not see the nested formgroup value displayed, make sure you have the following in the template after the closing <form> element.
Form Values : {{employeeForm.value}}

In our upcoming sessions we will discuss, form validation and dynamically adding form controls.

Video Link


Angular setvalue and patchvalue methods

Suggested Videos
Part 4 - Angular reactive forms tutorial | Text | Slides
Part 5 - Angular form control and form group | Text | Slides
Part 6 - Angular nested form groups | Text | Slides

In this video, we will discuss how to update HTML elements on a form with new data.


First let's understand why we need to update HTML elements on a form with new data. Let's say, we are using the form below to edit an existing employee. To be able to edit an existing employee details we have to retrieve data from a server and then update the form controls on the form with that retrieved data.

angular setvalue and patchvalue methods


This can be very easily achieved using setValue() method.

Modify the HTML in "create-employee.component.html" file to include "Load Data" button

angular setvalue vs patchvalue

I included "Load Data" button in the bootstrap panel footer. Please note that, I have wrapped both the buttons in a <div> element with "btn-toolbar" class so we get a space between the buttons. Otherwise, they will be joined together.

<div class="panel-footer">
  <div class="btn-toolbar">
  <button class="btn btn-primary" type="submit">Save</button>
  <button class="btn btn-primary" type="button"
          (click)="onLoadDataClick()">Load Data</button>
</div>

In the component class, include onLoadDataClick() method

onLoadDataClick(): void {
  this.employeeForm.setValue({
    fullName: 'Pragim Technologies',
    email: 'pragim@pragimtech.com',
    skills: {
      skillName: 'C#',
      experienceInYears: 5,
      proficiency: 'beginner'
    }
  });
}

At this point, when "Load Data" button is clicked, the form controls are updated with the form model data specified in onLoadDataClick() event handler.

Updating only a sub-set of HTML elements on the form : If I want to update only a sub-set of HTML elements on the form, can I still use setValue() method. The answer is NO. Let's see what happens if I use setValue() method and try to update only fullName and email fields.

Comment the code in onLoadDataClick() event handler as shown below.

onLoadDataClick(): void {
  this.employeeForm.setValue({
    fullName: 'Pragim Technologies',
    email: 'pragim@pragimtech.com',
    // skills: {
    //   skillName: 'C#',
    //   experienceInYears: 5,
    //   proficiency: 'beginner'
    // }
  });
}

At this point, when "Load Data" button is clicked, you will see the following error in the browser developer tools.
Must supply a value for form control with name: 'skills'

If you want to update only a sub-set of form controls, then use patchValue() method instead of setValue().

onLoadDataClick(): void {
  this.employeeForm.patchValue({
    fullName: 'Pragim Technologies',
    email: 'pragim@pragimtech.com',
    // skills: {
    //   skillName: 'C#',
    //   experienceInYears: 5,
    //   proficiency: 'beginner'
    // }
  });
}

At this point, when "Load Data" button is clicked, fullName and email form controls are updated as expected.

Can I use patchValue() to update all the formControls
Yes, you can use patchValue() to either update all the formControls or only a sub-set of form controls. In either cases, patchValue() method succeeds without any error. setValue() on the other hand can only be used to update all the form controls. You cannot use it to update a sub-set of form controls. If you try to, you will get an error. 

So setValue() is very useful when we want to update all the form controls. If we accidentally miss a value for a formcontrol, setValue() fails with an error so we know we are missing something. patchValue() on the other hand silently fails without an error. So, you may not realise you have missed something, especially when you have a very large form group.

So in short, use setValue() to update all form controls and patchValue() to update a sub-set of form controls

Video Link


Angular formbuilder example

Suggested Videos
Part 5 - Angular form control and form group | Text | Slides
Part 6 - Angular nested form groups | Text | Slides
Part 7 - Angular setvalue and patchvalue methods | Text | Slides

In this video we will discuss an easier way of creating reactive forms using the FormBuilder class


In Angular, there are 2 ways to create reactive forms
  1. Explicitly creating instances of FormGroup and FormControl classes using the new keyword. We discussed this in Part 4 and Part 6 of Angular 6 tutorial.
  2. Using the FormBuilder class

The FormBuilder class provides syntactic sugar that shortens creating instances of a FormControl, FormGroup, or FormArray. It reduces the amount of code we have to write to build complex reactive forms. The FormBuilder service has three methods: 
  • control() - Construct a new FormControl instance
  • group() - Construct a new FormGroup instance
  • array() - Construct a new FormArray instance
We will discuss FormArrays in our upcoming videos.

Step 1 : Import FormBuilder 

The FormBuilder class is provided as a service, so first let's import the service

import { FormBuilder } from '@angular/forms';

Step 2 : Inject the FormBuilder service 

Once the FormBuilder service is imported, inject it into the component using the constructor

constructor(private fb: FormBuilder) { }

Step 3 : Use the FormBuilder 
  • Notice in the example below, we are using the FormBuilder group() method to create a FormGroup instance. 
  • To the method we pass an object that contains a collection of child controls. 
  • For each child control we specify a key and value
  • Key is the name of the form control and the value is an array.
  • The first element of the array is used to specify an initial value for the form control.
  • The second and third elements of the array are used to specify synchronous and asynchronous validators for the form control. We will discuss these when we discuss form validation in our upcoming videos.
  • For now, we have defined just the initial value using the first element of the array.
  • We have specified an empty string as the default value for all the controls except proficiency radio buttons.
  • For proficiency we have a default value of beginner. So the respective radio button is selected when the form loads.
this.employeeForm = this.fb.group({
  fullName: [''],
  email: [''],
  skills: this.fb.group({
    skillName: [''],
    experienceInYears: [''],
    proficiency: ['beginner']
  }),
});

FormBuilder reduces the amount of boilerplate code we have to write to build complex reactive forms.

Video Link


Angular reactive forms validation

Suggested Videos
Part 6 - Angular nested form groups | Text | Slides
Part 7 - Angular setvalue and patchvalue methods | Text | Slides
Part 8 - Angular formbuilder example | Text | Slides

In this video we will discuss implementing validation in a reactive form.


Here is what we want to do. We want to make Full Name 
1. Required and
2. The number of characters must be between 2 and 10


Step 1 - Import Angular Validators class : The first thing to do, when implementing validation in a reactive form is to import angular's Validators class. 

import { Validators } from '@angular/forms';

This class has the following validator functions

Function Description
required Validate that a field has a value. Used for required fields. For example, Name is required.
requiredTrue Validate that the field value is true. This validator is commonly used on a required checkbox. For example, "I Agree to the terms" checkbox must be checked to submit the form.
email Validate that the field value has a valid email pattern. For example, abc is not a valid email.
pattern Validate that the field value matches the specified regex pattern.
min Validate that the field value is greater than or equal to the provided number. For example, minimum age to vote is 18.
max Validate that the field value is less than or equal to the provided number. For example, people over the age of 90 are not eligible for this insurance policy.
minLength The number of characters in the field must be greater than or equal to the provided minimum length. For example, Full Name must be at least 3 characters.
maxLength The number of characters in the field must be less than or equal to the provided maximum length. For example, Description cannot exceed 500 characters.

Most of our validation requirements can be met using one or more of the following built-in validator functions. You can also write your own custom validator, if your requirements are not met using one of the above built-in validator functions. We will discuss, implementing a custom validator in a reactive form in our upcoming videos.

Step 2 - Specify the validators on the fullName Field : Notice, along with a default value of empty string, we are passing an array of validator functions. In our case 3 - required, minLength and maxLength.

this.employeeForm = this.fb.group({
  fullName: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(10)]],
  // OtherFields...
});

Step 3 - Modify the fullName field in the template to display validation error messages.

<div class="form-group"
      [ngClass]="{'has-error': ((employeeForm.get('fullName').touched ||
                                 employeeForm.get('fullName').dirty) &&
                                 employeeForm.get('fullName').errors)}">
  <label class="col-sm-2 control-label" for="fullName">Full Name</label>
  <div class="col-sm-8">
    <input id="fullName" type="text" class="form-control" formControlName="fullName">
    <span class="help-block"
          *ngIf="((employeeForm.get('fullName').touched ||
                   employeeForm.get('fullName').dirty) &&
                   employeeForm.get('fullName').errors)">
      <span *ngIf="employeeForm.get('fullName').errors.required">
        Full Name is required
      </span>
      <span *ngIf="employeeForm.get('fullName').errors.minlength ||
                   employeeForm.get('fullName').errors.maxlength">
          Full Name must be greater than 2 characters and less than 10 characters
      </span>
    </span>
  </div>
</div>

At the moment, the validation messages are still in the template HTML. In our upcoming videos, we will discuss, how to move them into the component class.

Video Link


Angular form control valuechanges

Suggested Videos
Part 7 - Angular setvalue and patchvalue methods | Text | Slides
Part 8 - Angular formbuilder example | Text | Slides
Part 9 - Angular reactive forms validation | Text | Slides

In this video we will discuss how to monitor and react when a form control or form group value changes.


Angular valueChanges Observable
  • Both FormControl and FormGroup classes inherit from the base AbstractControl class
  • AbstractControl class has valueChanges property
  • valueChanges property is an observable that emits an event every time the value of the control changes
  • To be able to monitor and react when the FormControl or FormGroup value changes, subscribe to the valueChanges observable 
Angular form control valuechanges


For example, if you want to monitor and log to the console as the value of a fullName form control changes, subscribe to it's valueChanges observable as shown below.

ngOnInit() {

  this.employeeForm = this.fb.group({
    fullName: ['',
      [
        Validators.required,
        Validators.minLength(2),
        Validators.maxLength(10)]
    ],
    email: [''],
    skills: this.fb.group({
      skillName: ['C#'],
      experienceInYears: [''],
      proficiency: ['beginner']
    }),
  });

  // Subscribe to valueChanges observable
  this.employeeForm.get('fullName').valueChanges.subscribe(
    value => {
      console.log(value);
    }
  );

}

We placed the code to subscribe to the valueChanges Observable in ngOnInit lifecycle hook. This is because, we want to start monitoring and reacting to fullName form control value immediately after the component is initialised.

Every time the value of the fullName form control changes, the value is passed as a parameter to the subscribe method and the associated code is executed.

Since FormGroup class also inherit from AbstractControl class, we can also subscribe to the FormGroup valueChanges observable. This allows us to monitor and react when any control value in that FormGroup changes.

// Subscribe to FormGroup valueChanges observable
this.employeeForm.valueChanges.subscribe(
  value => {
    console.log(JSON.stringify(value));
  }
);

Subscribing to valueChanges observable and there by monitoring a form control or form group allow us to do several things like
  • Implementing auto-complete feature
  • Dynamically validating form controls
  • Move validation messages from the view template to the component class
We will discuss, how to do all of the above in our upcoming videos.

Video Link


Loop through all form controls in formgroup in reactive form

Suggested Videos
Part 8 - Angular formbuilder example | Text | Slides
Part 9 - Angular reactive forms validation | Text | Slides
Part 10 - Angular form control valuechanges | Text | Slides

In this video we will discuss, how to loop through all form controls in a formgroup including nested form groups in a reactive form.


Understanding this technique is very useful, as it can help us perform the following on all the form controls in a reactive form
  • Reset form controls
  • Enable or disable all form controls or just the nested formgroup controls
  • Set validators and clear validators
  • Mark form controls as dirty, touched, untouched, pristine etc.
  • Move validation messages and the logic to show and hide them into the component class from the view template.

Here is what we want to do : Loop through each form control in the following employeeForm form group including nested skills form group and log the form control key and value to the console.

this.employeeForm = this.fb.group({
  fullName: [''],
  email: [''],
  skills: this.fb.group({
    skillName: [''],
    experienceInYears: [''],
    proficiency: ['beginner']
  }),
});

For example, if we have the following sample data on the form

Loop through all form controls in formgroup in reactive form

We want every form control key and value to be logged to the console as shown below.

recursive loop through form controls in form groups

Here is the method. It is commented and self-explanatory

logKeyValuePairs(group: FormGroup): void {
  // loop through each key in the FormGroup
  Object.keys(group.controls).forEach((key: string) => {
    // Get a reference to the control using the FormGroup.get() method
    const abstractControl = group.get(key);
    // If the control is an instance of FormGroup i.e a nested FormGroup
    // then recursively call this same method (logKeyValuePairs) passing it
    // the FormGroup so we can get to the form controls in it
    if (abstractControl instanceof FormGroup) {
      this.logKeyValuePairs(abstractControl);
      // If the control is not a FormGroup then we know it's a FormControl
    } else {
      console.log('Key = ' + key + ' && Value = ' + abstractControl.value);
    }
  });
}

In our next video we will discuss, moving validation messages into the component class from the view template.

Video Link


Move validation messages to the component class in reactive form

Suggested Videos
Part 9 - Angular reactive forms validation | Text | Slides
Part 10 - Angular form control valuechanges | Text | Slides
Part 11 - Loop through all form controls in formgroup in reactive form | Text | Slides

In this video we will discuss, how to move validation messages to the component class. There are several benefits to this
  • Easily unit test validation logic
  • Instead of hard-coding validation messages in the application, we can load them from an external source like a database or a file.
  • Change validation dynamically at run-time based on the decisions made in code or user selections

In this video let's move the validation messages to the component class and in our next video we will discuss moving the logic to show and hide these messages.


Changes in create-employee.component.ts file : 

// This object will hold the messages to be displayed to the user
// Notice, each key in this object has the same name as the
// corresponding form control
formErrors = {
  'fullName': '',
  'email': '',
  'skillName': '',
  'experienceInYears': '',
  'proficiency': ''
};

// This object contains all the validation messages for this form
validationMessages = {
  'fullName': {
    'required': 'Full Name is required.',
    'minlength': 'Full Name must be greater than 2 characters.',
    'maxlength': 'Full Name must be less than 10 characters.'
  },
  'email': {
    'required': 'Email is required.'
  },
  'skillName': {
    'required': 'Skill Name is required.',
  },
  'experienceInYears': {
    'required': 'Experience is required.',
  },
  'proficiency': {
    'required': 'Proficiency is required.',
  },
};

ngOnInit() {
  // Modify the code to include required validators on
  // all form controls
  this.employeeForm = this.fb.group({
    fullName: ['', [Validators.required,
    Validators.minLength(2), Validators.maxLength(10)]],
    email: ['', Validators.required],
    skills: this.fb.group({
      skillName: ['', Validators.required],
      experienceInYears: ['', Validators.required],
      proficiency: ['', Validators.required]
    }),
  });
}

logValidationErrors(group: FormGroup): void {
  // Loop through each control key in the FormGroup
  Object.keys(group.controls).forEach((key: string) => {
    // Get the control. The control can be a nested form group
    const abstractControl = group.get(key);
    // If the control is nested form group, recursively call
    // this same method
    if (abstractControl instanceof FormGroup) {
      this.logValidationErrors(abstractControl);
      // If the control is a FormControl
    } else {
      // Clear the existing validation errors
      this.formErrors[key] = '';
      if (abstractControl && !abstractControl.valid) {
        // Get all the validation messages of the form control
        // that has failed the validation
        const messages = this.validationMessages[key];
        // Find which validation has failed. For example required,
        // minlength or maxlength. Store that error message in the
        // formErrors object. The UI will bind to this object to
        // display the validation errors
        for (const errorKey in abstractControl.errors) {
          if (errorKey) {
            this.formErrors[key] += messages[errorKey] + ' ';
          }
        }
      }
    }
  });
}

onLoadDataClick(): void {
  this.logValidationErrors(this.employeeForm);
  console.log(this.formErrors);
}

Video Link


Move validation logic to the component class in reactive form

Suggested Videos
Part 10 - Angular form control valuechanges | Text | Slides
Part 11 - Loop through all form controls in formgroup in reactive form | Text | Slides
Part 12 - Move validation messages to the component class in reactive form | Text | Slides

In this video we will discuss, how to move the logic to show and hide validation messages from the view template into the component class. This is continuation to Part 12 where we discussed moving validation messages.


create-employee.component.html : Consider the following HTML in CreateEmployeeComponent view template. This HTML is for the "Full Name" field. The logic to add or remove has-error class is in the template. Also the validation message and the logic to show and hide it is also in the template at the moment.


<div class="form-group"
      [ngClass]="{'has-error': ((employeeForm.get('fullName').touched ||
                                employeeForm.get('fullName').dirty) &&
                                employeeForm.get('fullName').errors)}">
  <label class="col-sm-2 control-label" for="fullName">Full Name</label>
  <div class="col-sm-8">
    <input id="fullName" type="text" class="form-control" formControlName="fullName">
    <span class="help-block" *ngIf="((employeeForm.get('fullName').touched ||
                                      employeeForm.get('fullName').dirty) &&
                                      employeeForm.get('fullName').errors)">
      <span *ngIf="employeeForm.get('fullName').errors.required">
        Full Name is required
      </span>
      <span *ngIf="employeeForm.get('fullName').errors.minlength ||
                    employeeForm.get('fullName').errors.maxlength">
        Full Name must be greater than 2 characters and less than 10 characters
      </span>
    </span>
  </div>
</div>

Now, let's move all of this into the component class. Modify the HTML as shown below. Notice, now we are binding to formErrors.fullName property. All the complex logic is moved to the component class. Notice the HTML here is much less than what we have had before.

<div class="form-group" [ngClass]="{'has-error': formErrors.fullName}">
  <label class="col-sm-2 control-label" for="fullName">Full Name</label>
  <div class="col-sm-8">
    <input id="fullName" type="text" class="form-control" formControlName="fullName">
    <span class="help-block" *ngIf="formErrors.fullName">
      {{formErrors.fullName}}
    </span>
  </div>
</div>

Changes in create-employee.component.ts file : The changes are commented and self-explanatory

formErrors = {
  'fullName': '',
  'email': '',
  'skillName': '',
  'experienceInYears': '',
  'proficiency': ''
};

validationMessages = {
  'fullName': {
    'required': 'Full Name is required.',
    'minlength': 'Full Name must be greater than 2 characters.',
    'maxlength': 'Full Name must be less than 2 characters.',
  },
  'email': {
    'required': 'Email is required.'
  },
  'skillName': {
    'required': 'Skill Name is required.',
  },
  'experienceInYears': {
    'required': 'Experience is required.',
  },
  'proficiency': {
    'required': 'Proficiency is required.',
  },
};

ngOnInit() {

  this.employeeForm = this.fb.group({
    fullName: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(10)]],
    email: ['', Validators.required],
    skills: this.fb.group({
      skillName: ['', Validators.required],
      experienceInYears: ['', Validators.required],
      proficiency: ['', Validators.required]
    }),
  });

  // When any of the form control value in employee form changes
  // our validation function logValidationErrors() is called
  this.employeeForm.valueChanges.subscribe((data) => {
    this.logValidationErrors(this.employeeForm);
  });

}

logValidationErrors(group: FormGroup = this.employeeForm): void {
  Object.keys(group.controls).forEach((key: string) => {
    const abstractControl = group.get(key);
    if (abstractControl instanceof FormGroup) {
      this.logValidationErrors(abstractControl);
    } else {
      this.formErrors[key] = '';
      if (abstractControl && !abstractControl.valid
          && (abstractControl.touched || abstractControl.dirty)) {
        const messages = this.validationMessages[key];
        for (const errorKey in abstractControl.errors) {
          if (errorKey) {
            this.formErrors[key] += messages[errorKey] + ' ';
          }
        }
      }
    }
  });
}

The only problem at the moment is that when a control loses focus, our validation is not triggered. This is because valueChanges observable does not emit an event when the control loses focus. It only emits an event when the value changes.

One work around for this is to bind to the blur event and call validation function (logValidationErrors()) manually.

<input id="fullName" type="text" class="form-control"
        formControlName="fullName" (blur)="logValidationErrors()">

Here is the HTML for Email, Skill Name, Experience and Proficiency input elements. 

<div class="form-group" [ngClass]="{'has-error': formErrors.email}">
  <label class="col-sm-2 control-label" for="email">Email</label>
  <div class="col-sm-8">
    <input id="email" type="text" class="form-control"
           formControlName="email" (blur)="logValidationErrors()">
    <span class="help-block" *ngIf="formErrors.email">
      {{formErrors.email}}
    </span>
  </div>
</div>

<div class="well">
  <div formGroupName="skills">

    <div class="form-group" [ngClass]="{'has-error': formErrors.skillName}">
      <label class="col-sm-2 control-label" for="skillName">
        Skill
      </label>
      <div class="col-sm-4">
        <input type="text" class="form-control" id="skillName" formControlName="skillName"
               (blur)="logValidationErrors()" placeholder="C#, Java, Angular etc...">
        <span class="help-block" *ngIf="formErrors.skillName">
          {{formErrors.skillName}}
        </span>
      </div>
    </div>

    <div class="form-group" [ngClass]="{'has-error': formErrors.experienceInYears}">
      <label class="col-sm-2 control-label" for="experienceInYears">
        Experience
      </label>
      <div class="col-sm-4">
        <input type="text" class="form-control" id="experienceInYears"
               formControlName="experienceInYears" placeholder="In Years"
              (blur)="logValidationErrors()">
        <span class="help-block" *ngIf="formErrors.experienceInYears">
          {{formErrors.experienceInYears}}
        </span>
      </div>
    </div>

    <div class="form-group" [ngClass]="{'has-error': formErrors.proficiency}">
      <label class="col-md-2 control-label">Proficiency</label>
      <div class="col-md-8">
        <label class="radio-inline">
          <input type="radio" value="beginner" formControlName="proficiency"
                 (blur)="logValidationErrors()">Beginner
        </label>
        <label class="radio-inline">
          <input type="radio" value="intermediate" formControlName="proficiency"
                 (blur)="logValidationErrors()">Intermediate
        </label>
        <label class="radio-inline">
          <input type="radio" value="advanced" formControlName="proficiency"
                 (blur)="logValidationErrors()">Advanced
        </label>
        <span class="help-block" *ngIf="formErrors.experienceInYears">
          {{formErrors.proficiency}}
        </span>
      </div>
    </div>
  </div>
</div>

Video Link


Dynamically adding or removing form control validators in reactive form

Suggested Videos
Part 11 - Loop through all form controls in formgroup in reactive form | Text | Slides
Part 12 - Move validation messages to the component class in reactive form | Text | Slides
Part 13 - Move validation logic to the component class in reactive form | Text | Slides

In this video we will discuss how to add or remove validators dynamically at runtime.


Let us understand this with an example. To start with, Phone filed is optional.

angular reactive forms dynamic validation


However, if we select "Phone" as the contact preference, then it should become a required field.

angular reactive forms dynamic required

So here is our requirement 
  • Add the "required" validator to the Phone form control when the user selects "Phone" as their contact preference
  • On the other hand, remove the "required" validator from the Phone form control, when the user selects "Email" as their contact preference
  • So on the "Phone" form control, we have to dynamically add or remove the required validator function
This can be very easily achieved using the following 3 functions
  • setValidators()
  • clearValidators()
  • updateValueAndValidity()
These methods are available in the AbstractControl class. Since FormControl inherits from AbstractControl, these methods are also available to FormControl class.

Here is the HTML

<!-- Notice the click event handler on both the radio buttons. When "Email"
radio button is clicked "email" string is passed to the event handler
function. Similarly, when "Phone" radio button is clicked "phone"
string is passed to the event handler function -->

<div class="form-group">
  <label class="col-md-2 control-label">Contact Preference</label>
  <div class="col-md-8">
    <label class="radio-inline">
      <input type="radio" value="email" formControlName="contactPreference"
              (click)="onContactPrefernceChange('email')">Email
    </label>
    <label class="radio-inline">
      <input type="radio" value="phone" formControlName="contactPreference"
              (click)="onContactPrefernceChange('phone')">Phone
    </label>
  </div>
</div>

<!-- Email input element -->
<div class="form-group" [ngClass]="{'has-error': formErrors.email}">
  <label class="col-sm-2 control-label" for="email">Email</label>
  <div class="col-sm-8">
    <input id="email" type="text" class="form-control"
            formControlName="email" (blur)="logValidationErrors()">
    <span class="help-block" *ngIf="formErrors.email">
      {{formErrors.email}}
    </span>
  </div>
</div>

<!-- Phone input element -->
<div class="form-group" [ngClass]="{'has-error': formErrors.phone}">
  <label class="col-sm-2 control-label" for="email">Phone</label>
  <div class="col-sm-8">
    <input id="phone" type="text" class="form-control"
            formControlName="phone" (blur)="logValidationErrors()">
    <span class="help-block" *ngIf="formErrors.phone">
      {{formErrors.phone}}
    </span>
  </div>
</div>

Component class code

// Include phone property
formErrors = {
  'fullName': '',
  'email': '',
  'phone': '',
  'skillName': '',
  'experienceInYears': '',
  'proficiency': ''
};

// Include required error message for phone form control
validationMessages = {
  'fullName': {
    'required': 'Full Name is required.',
    'minlength': 'Full Name must be greater than 2 characters',
    'maxlength': 'Full Name must be less than 10 characters.',
  },
  'email': {
    'required': 'Email is required.',
    'emailDomain': 'Email domian should be prgaimtech.com'
  },
  'phone': {
    'required': 'Phone is required.'
  },
  'skillName': {
    'required': 'Skill Name is required.',
  },
  'experienceInYears': {
    'required': 'Experience is required.',
  },
  'proficiency': {
    'required': 'Proficiency is required.',
  },
};

ngOnInit() {
  // Include FormControls for contactPreference, email & phone
  // contactPreference has email as the default value
  this.employeeForm = this.fb.group({
    fullName: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(10)]],
    contactPreference: ['email'],
    email: ['', Validators.required],
    phone: [''],
    skills: this.fb.group({
      skillName: ['', Validators.required],
      experienceInYears: ['', Validators.required],
      proficiency: ['', Validators.required]
    }),
  });

  this.employeeForm.valueChanges.subscribe((data) => {
    this.logValidationErrors(this.employeeForm);
  });
}

// If the Selected Radio Button value is "phone", then add the
// required validator function otherwise remove it
onContactPrefernceChange(selectedValue: string) {
  const phoneFormControl = this.employeeForm.get('phone');
  if (selectedValue === 'phone') {
    phoneFormControl.setValidators(Validators.required);
  } else {
    phoneFormControl.clearValidators();
  }
  phoneFormControl.updateValueAndValidity();
}

We can also achieve the same thing by subscribing to the valueChanges observable of contactPreference radio button in code, instead of binding to the click event in the HTML. The benefit of this approach is that, our code is easier to unit test.

Here are the steps

Step 1 : In the HTML remove click event binding from both the radio buttons (email and phone)

<div class="form-group">
  <label class="col-md-2 control-label">Contact Preference</label>
  <div class="col-md-8">
    <label class="radio-inline">
      <input type="radio" value="email" formControlName="contactPreference">Email
    </label>
    <label class="radio-inline">
      <input type="radio" value="phone" formControlName="contactPreference">Phone
    </label>
  </div>
</div>

Step 2 : Subscribe to contactPreference form control valueChanges observable

this.employeeForm.get('contactPreference')
                 .valueChanges.subscribe((data: string) => {
  this.onContactPrefernceChange(data);
});

Video Link


Angular reactive form custom validator

Suggested Videos
Part 12 - Move validation messages to the component class in reactive form | Text | Slides
Part 13 - Move validation logic to the component class in reactive form | Text | Slides
Part 14 - Dynamically adding or removing form control validators in reactive form | Text | Slides

In this video we will discuss, creating and using a custom validator in an Angular reactive form.


Angular provides several built-in validator functions like required, pattern, minLength, maxLength, etc. Most of our application validation requirements can be met using one or more of the these built-in validator functions. However, sometimes we may need custom validation logic.


For example, 
let's say we only want to allow an email address with pragimtech.com as the domain. 

Angular reactive form custom validator

Any other email domain is invalid. 

angular reactive form add custom validator

We can achieve this very easily using a custom validator. Here are the steps.

Step 1 : Create the custom validator function

function emailDomain(control: AbstractControl): { [key: string]: any } | null {
  const email: string = control.value;
  const domain = email.substring(email.lastIndexOf('@') + 1);
  if (email === '' || domain.toLowerCase() === 'pragimtech.com') {
    return null;
  } else {
    return { 'emailDomain': true };
  }
}

Just like a builtin validator, a custom validator is also a function. If you take a look at the required built-in function, notice it takes AbstractControl as a parameter. Both FormControl and FormGroup inherits from AbstractControl class. Specifying AbstractControl as parameter type, allows us to pass either a FormControl or a FormGroup to validate.

required(control: AbstractControl): ValidationErrors | null;

Notice the return type is either ValidationErrors object or null. The method returns null if the control passes validation otherwise ValidationErrors object. If you take a look at the definition of ValidationErrors type, it is an object with a key and a value. Key is a string and value can be anything. But we usually specify a value of true to indicate that there is a validation error.

{ [key: string]: any }

In the template, we use this same key to display the validation error message.

Step 2 : Attach the custom validator function to the control that we want to validate

email: ['', [Validators.required, emailDomain]]

Step 3 : Display the validation error message

If you want the validation error message and logic in the template, then check for emailDomin key on the errors collection of email form control

<span *ngIf="employeeForm.get('email').errors.emailDomain">
  Email domian should be prgaimtech.com
</span>

On the other hand, if you want the validation error message and logic in the component class, then include the validation message in validationMessages object as shown below.

validationMessages = {
  'fullName': {...
  },
  'email': {
    'required': 'Email is required.',
    'emailDomain': 'Email domian should be pragimtech.com'
  },
  'phone': {...
  },
  'skillName': {...
  },
  'experienceInYears': {...
  },
  'proficiency': {...
  },
};

Here is the formErrors object which holds the messages to display. The template will bind to this object.

formErrors = {
  'fullName': '',
  'email': '',
  'phone': '',
  'skillName': '',
  'experienceInYears': '',
  'proficiency': ''
};

This logValidationErrors() method checks if a control has failed validation. If it has, it populates the formErrors object, with the validation error message using the form control name as the key.

logValidationErrors(group: FormGroup = this.employeeForm): void {
  Object.keys(group.controls).forEach((key: string) => {
    const abstractControl = group.get(key);
    if (abstractControl instanceof FormGroup) {
      this.logValidationErrors(abstractControl);
    } else {
      this.formErrors[key] = '';
      if (abstractControl && !abstractControl.valid
        && (abstractControl.touched || abstractControl.dirty)) {
        const messages = this.validationMessages[key];
        for (const errorKey in abstractControl.errors) {
          if (errorKey) {
            this.formErrors[key] += messages[errorKey] + ' ';
          }
        }
      }
    }
  });
}

In the template bind to the email property on the formErrors object

<div class="form-group" [ngClass]="{'has-error': formErrors.email}">
  <label class="col-sm-2 control-label" for="email">Email</label>
  <div class="col-sm-8">
    <input id="email" type="text" class="form-control"
            formControlName="email" (blur)="logValidationErrors()">
    <span class="help-block" *ngIf="formErrors.email">
      {{formErrors.email}}
    </span>
  </div>
</div>

Video Link


Angular reactive form custom validator with parameter

Suggested Videos
Part 13 - Move validation logic to the component class in reactive form | Text | Slides
Part 14 - Dynamically adding or removing form control validators in reactive form | Text | Slides
Part 15 - Angular reactive form custom validator | Text | Slides

In this video we will discuss creating and using a custom validator with parameters. This is continuation to Part 15. Please watch Part 15 from Angular 6 tutorial before proceeding.


In our previous video we discussed creating a custom email domain validator. The following is that validator function.

function emailDomain(control: AbstractControl): { [key: string]: any } | null {
  const email: string = control.value;
  const domain = email.substring(email.lastIndexOf('@') + 1);
  if (email === '' || domain.toLowerCase() === 'pragimtech.com') {
    return null;
  } else {
    return { 'emailDomain': true };
  }
}


Notice, the domain name 'pragimtech.com' is hard coded. So this custom validator, only works if you want to check if the domain is pragimtech.com. What if you want to check another domain like microsoft.com. We want to make this custom validator reusable with any domain name. We should be able to pass the domain name as a parameter to the emailDomain custom validator function.

Notice in the example below, we are passing pragimtech.com as the domain name. If you want to check for a different domain, you simply pass that domain name as a parameter.

email: ['', [emailDomain('pragimtech.com')]]

The following built-in validators have parameters.
  • min
  • max
  • minlength
  • maxlength
Notice the min() built-in validator function. It takes in a number as a parameter and returns ValidatorFn.

min(min: number): ValidatorFn;

So, what is ValidatorFn?
ValidatorFn stands from validator function. So this min() function is taking in a number as a parameter and returns a validator function. If you understand the concept of closure in JavaScript, then this is very easy to understand. We discussed closures in detail in Parts 27 and 28 of JavaScript tutorial.

In simple terms, you can thinks of a closure as, a function inside another function i.e an inner function and an outer function. The inner function has access to the outer function’s variables and parameters in addition to it's own variables and parameters.

Now that task at hand for us, is to convert our emailDomain() function to take in the domain name as a parameter and return a validator function. To be able to do this we are going to take the advantage of closures in JavaScript.

ValidatorFn is an interface and the signature of the function it returns is as shown below. It takes the AbstractControl that we want to validate as an input parameter and returns null or ValidationErrors object. Null if the validation succeeds and a ValidationErrors object is the validation has failed.

(c: AbstractControl): ValidationErrors | null;

Custom Validator with parameter

function emailDomain(domainName: string) {
  return (control: AbstractControl): { [key: string]: any } | null => {
    const email: string = control.value;
    const domain = email.substring(email.lastIndexOf('@') + 1);
    if (email === '' || domain.toLowerCase() === domainName.toLowerCase()) {
      return null;
    } else {
      return { 'emailDomain': true };
    }
  };
}

Code Explanation
  • We have 2 functions here. An inner function and an outer function.
  • The outer function has a name (emailDomain), but the inner function does not have a name. It is an anonymous function.
  • The inner anonymous function has access to the outer function parameter domainName.
  • You can have as many parameters as you want in the outer function, then inner function will have access to all of them in addition to it's own parameters.
Passing the value for the custom validator parameter

email: ['', [Validators.required, emailDomain('dell.com')]]

Finally do not forget to updated the validation error message in the validationMessages structure

validationMessages = {
  'email': {
    'required': 'Email is required.',
    'emailDomain': 'Email domian should be dell.com'
  },
  'proficiency': {
    'required': 'Proficiency is required.',
  },
};

Video Link


Angular Reusable Custom Validator

Suggested Videos
Part 14 - Dynamically adding or removing form control validators in reactive form | Text | Slides
Part 15 - Angular reactive form custom validator | Text | Slides
Part 16 - Angular reactive form custom validator with parameter | Text | Slides

In this video we will discuss how to make a custom validator reusable in Angular.


The built-in validators in angular like the following, are reusable. This means we can use them with any form control on any angular form. 
  • required
  • min
  • max
  • minlength
  • maxlength
  • pattern

To be able to use one of the built-in angular validator, all we have to do is import the Validators class from '@angular/forms' package.

import { Validators } from '@angular/forms';

Once the Validators class is imported, use the validator functions on the form control that you want to validate.

fullName: ['', [Validators.required, Validators.minLength(2)]]

All the buil-in validator functions are marked as static functions in the Validators class. This allows us to use the validator functions, without the need to create an instance of the Validators class.

Along the same lines let's make our emailDomain custom validator function reusable by including it as a static function in a separate class.

We want to make this validator function available to all form controls on all forms. So, create a shared folder. In the shared folder, create a file with name custom.validators.ts and include the following code.

import { AbstractControl } from '@angular/forms';

export class CustomValidators {
    static emailDomain(domainName: string) {
        return (control: AbstractControl): { [key: string]: any } | null => {
            const email: string = control.value;
            const domain = email.substring(email.lastIndexOf('@') + 1);
            if (email === '' || domain.toLowerCase() === domainName.toLowerCase()) {
                return null;
            } else {
                return { 'emailDomain': true };
            }
        };
    }
}

Using the reusable Custom Validators : First, Import the CustomValidators class. Just like how we import the built-in Validators class, import the CustomValidators class from custom.validators.ts file.

import { CustomValidators } from '../shared/custom.validators';

Tie the validator function to a form control that you want to validate.

email: ['', [CustomValidators.emailDomain('dell.com')]]

Video Link


Angular reactive forms cross field validation

Suggested Videos
Part 15 - Angular reactive form custom validator | Text | Slides
Part 16 - Angular reactive form custom validator with parameter | Text | Slides
Part 17 - How to make angular custom validator reusable | Text | Slides

In this video we will discuss cross field validation in a reactive form.


Let us understand this with an example. We want to ensure Email and Confirm Email fields have the same value. If they do not match, we want to display a validation message.

angular reactive cross field validation


ConfirmEmail field is required and if no value is present it should display the required validation error.

angular 6 cross field validation

So in short, here is the requirement
  • Confirm Email field is required and if a value is present it should match with the Email field value.
  • If no value is entered, it should display required error
  • If a value is present and does not match with Email field, it should display do not match validation error
To validate if Email and Confirm Email fields have same value, we need to compare 2 Form Controls. If you look at a Validator function in Angular, it only accepts either a FormGroup or a FormControl as a parameter. We cannot pass 2 form controls to the validator function, but what we can do is group them using a nested formgroup and then pass that nested formgroup as a parameter to the Validator function.

Changes in the Template (create-employee.component.html)

<div formGroupName="emailGroup">
  <div class="form-group" [ngClass]="{'has-error': formErrors.email}">
    <label class="col-sm-2 control-label" for="email">Email</label>
    <div class="col-sm-8">
      <input id="email" type="text" class="form-control"
             formControlName="email" (blur)="logValidationErrors()">
      <span class="help-block" *ngIf="formErrors.email">
        {{formErrors.email}}
      </span>
    </div>
  </div>

  <div class="form-group" [ngClass]="{'has-error': formErrors.confirmEmail
                                                || formErrors.emailGroup}">
    <label class="col-sm-2 control-label" for="confirmEmail">
      Confirm Email
    </label>
    <div class="col-sm-8">
      <input id="confirmEmail" type="text" class="form-control"
             formControlName="confirmEmail" (blur)="logValidationErrors()">
      <span class="help-block"
            *ngIf="formErrors.confirmEmail || formErrors.emailGroup">
        {{formErrors.confirmEmail ? formErrors.confirmEmail
          : formErrors.emailGroup}}
      </span>
    </div>
  </div>
</div>
  • Notice email and confirmEmail form controls are nested in a formgroup with name emailGroup
  • Bootstrap has-error class is conditionally added if either confirmEmail or emailGroup properties of the formErrors object are truthy
  • confirmEmail property stores required error - Confirm Email is required.
  • emailGroup property stores do not match error - Email and Confirm Email do not match
  • We do not have these 2 properties on the formErrors object yet. We will add them in the component class in just a bit.
  • Similarly, the span element that displays the validation error is bound to confirmEmail or emailGroup properties of the formErrors object. So the span element is displayed only if either of the properties are truthy.
If the Email form control has a value and if nothing is filled in the confirmEmail form control, we do not want both the required error and do not match error to be displayed. The following interpolation expression, ensures to display the right validation message.

{{formErrors.confirmEmail ? formErrors.confirmEmail : formErrors.emailGroup}}

Changes in the Component Clas (create-employee.component.ts) : The changes are commented and self-explanatory.

// Group properties on the formErrors object. The UI will bind to these properties
// to display the respective validation messages
formErrors = {
  'fullName': '',
  'email': '',
  'confirmEmail': '',
  'emailGroup': '',
  'phone': '',
  'skillName': '',
  'experienceInYears': '',
  'proficiency': ''
};

// This structure stoes all the validation messages for the form Include validation
// messages for confirmEmail and emailGroup properties. Notice to store the
// validation message for the emailGroup we are using emailGroup key. This is the
// same key that the matchEmails() validation function below returns, if the email
// and confirm email do not match.
validationMessages = {
  'fullName': {
    'required': 'Full Name is required.',
    'minlength': 'Full Name must be greater than 2 characters',
    'maxlength': 'Full Name must be less than 10 characters.',
  },
  'email': {
    'required': 'Email is required.',
    'emailDomain': 'Email domian should be dell.com'
  },
  'confirmEmail': {
    'required': 'Confirm Email is required.'
  },
  'emailGroup': {
    'emailMismatch': 'Email and Confirm Email do not match.'
  },
  'phone': {
    'required': 'Phone is required.'
  },
  'skillName': {
    'required': 'Skill Name is required.',
  },
  'experienceInYears': {
    'required': 'Experience is required.',
  },
  'proficiency': {
    'required': 'Proficiency is required.',
  },
};

// email and confirmEmail form controls are grouped using a nested form group
// Notice, the validator is attached to the nested emailGroup using an object
// with key validator. The value is our validator function matchEmails() which
// is defined below. The important point to keep in mind is when the validation
// fails, the validation key is attached the errors collection of the emailGroup
// This is the reason we added emailGroup key both to formErrors object and
// validationMessages object.
ngOnInit() {
  this.employeeForm = this.fb.group({
    fullName: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(10)]],
    contactPreference: ['email'],
    emailGroup: this.fb.group({
      email: ['', [Validators.required, emailDomain('dell.com')]],
      confirmEmail: ['', [Validators.required]],
    }, { validator: matchEmails }),
    phone: [''],
    skills: this.fb.group({
      skillName: ['', Validators.required],
      experienceInYears: ['', Validators.required],
      proficiency: ['', Validators.required]
    }),
  });

  this.employeeForm.valueChanges.subscribe((data) => {
    this.logValidationErrors(this.employeeForm);
  });

  this.employeeForm.get('contactPreference').valueChanges.subscribe((data: string) => {
    this.onContactPrefernceChange(data);
  });
}

logValidationErrors(group: FormGroup = this.employeeForm): void {
  Object.keys(group.controls).forEach((key: string) => {
    const abstractControl = group.get(key);
    this.formErrors[key] = '';
    // Loop through nested form groups and form controls to check
    // for validation errors. For the form groups and form controls
    // that have failed validation, retrieve the corresponding
    // validation message from validationMessages object and store
    // it in the formErrors object. The UI binds to the formErrors
    // object properties to display the validation errors.
    if (abstractControl && !abstractControl.valid
      && (abstractControl.touched || abstractControl.dirty)) {
      const messages = this.validationMessages[key];
      for (const errorKey in abstractControl.errors) {
        if (errorKey) {
          this.formErrors[key] += messages[errorKey] + ' ';
        }
      }
    }

    if (abstractControl instanceof FormGroup) {
      this.logValidationErrors(abstractControl);
    }
  });
}

Finally, include the following validator function in create-employee.component.ts file, after the closing curly brace (}) of the CreateEmployeeComponent class.

// Nested form group (emailGroup) is passed as a parameter. Retrieve email and
// confirmEmail form controls. If the values are equal return null to indicate
// validation passed otherwise an object with emailMismatch key. Please note we
// used this same key in the validationMessages object against emailGroup
// property to store the corresponding validation error message
function matchEmails(group: AbstractControl): { [key: string]: any } | null {
  const emailControl = group.get('email');
  const confirmEmailControl = group.get('confirmEmail');

  if (emailControl.value === confirmEmailControl.value || confirmEmailControl.pristine) {
    return null;
  } else {
    return { 'emailMismatch': true };
  }
}

Video Link


Angular formarray example

Suggested Videos
Part 16 - Angular reactive form custom validator with parameter | Text | Slides
Part 17 - How to make angular custom validator reusable | Text | Slides
Part 18 - Angular reactive forms cross field validation | Text | Slides

In this video we will discuss FormArray in Angular

To build an Angular Reactive Form we use three fundamental building blocks
  • FormControl
  • FormGroup
  • FormArray

We discussed FormControl and FormGroup in our previous videos in this series. In this video we will discuss FormArray in Angular.


A FormArray as the name implies is an array. It can contain an array of 
  • FormControls
  • FormGroups
  • Nested FormArrays
We usually use an array to hold like items, but a FormArray can contain unlike items as well, i.e a few elements in a given array can be FormControls, a few of them in that same array can be FormGroups and the rest of them can be FormArrays.

In the example below, we have a FormArray with 
  • one FormControl
  • one FormGroup
  • one FormArray
const formArray = new FormArray([
  new FormControl('John', Validators.required),
  new FormGroup({
    country: new FormControl('', Validators.required)
  }),
  new FormArray([])
]);

To programmatically find the number of elements in a FormArray use the length property

formArray.length

To iterate over a FormArray you can use a for loop. Use instanceof operator to determine if the control that you are currently dealing with is a FormControl, FormGroup or FormArray.

for (const control of formArray.controls) {
  if (control instanceof FormControl) {
    console.log('control is FormControl');
  }
  if (control instanceof FormGroup) {
    console.log('control is FormGroup');
  }
  if (control instanceof FormArray) {
    console.log('control is FormArray');
  }
}

There are 2 ways to create a FormArray in Angular. Using the new keyword or FormBuilder class.

Create a FormArray, using the new keyword

const formArray = new FormArray([
  new FormControl('John', Validators.required),
  new FormControl('IT', Validators.required),
]);

Create a FormArray, using the array() method of the FormBuilder class

const formArray = this.fb.array([
  new FormControl('John', Validators.required),
  new FormControl('IT', Validators.required),
]);

Although, we can use a FormArray to store unlike items, we generally use it to store like items. For example, an array of 
  • FormControls
  • FormGroups
  • or Nested FormArrays
The value property of a FormArray, returns an array containing values of each child FormControl

const formArray = this.fb.array([
  new FormControl('John', Validators.required),
  new FormControl('IT', Validators.required),
  new FormControl('', Validators.required),
]);

formArray.value returns
["John", "IT", ""]

We usually use the following properties to determine the state of a FormControl or a FormGroup. These status properties are also available on a FormArray. For example, if one of the controls in a FormArray is touched, the entire array becomes touched. Similarly, if one of the controls is invalid, the entire array becomes invalid.
  • touched
  • untouched
  • dirty
  • pristine
  • valid
  • invalid
Useful FormArray methods
Method Purpose
push Inserts the control at the end of the array
insert Inserts the control at the specified index in the array
removeAt Removes the control at the specified index in the array
setControl Replace an existing control at the specified index in the array
at Return the control at the specified index in the array

We can also use a FormGroup to create a group of FormControls. Notice, in the example below, we are using the group() method of the FormBuilder class to create a FormGroup.

const formGroup = this.fb.group([
  new FormControl('John', Validators.required),
  new FormControl('IT', Validators.required),
  new FormControl('', Validators.required),
]);

What is the difference between a FormGroup and a FormArray?
Well, in many aspects they are similar. However, one major difference is that a FormArray data is serialized as an array where as a FormGroup is serialized as an object. 

To see this, log the FormGroup and FormArray instance to the browser console. In the case of FormArray, controls property contains an array of form controls. Where as, in the case of FormGroup, controls property contains an object with key/value pairs, where key is the name of the form control and value is an instance of FormControl.

console.log(formArray.value); 
Output: [FormControl, FormControl, FormControl]

console.log(formGroup.value);
Output: {0: FormControl, 1: FormControl, 2: FormControl}

The fact that FormArray tracks FormControls as part of an array is very useful, when we want to generate FormControls and FormGroups dynamically. For example, let's say you are filling an employment form, and you want to add multiple skills. We cannot have a fixed number of skill related fields on the form as they are dependant on the employee experience. This is one example where we need to generate form controls dynamically, and a FormArray is a perfect choice for implementing this. 

We will discuss generating employee skill related fields dynamically in our next video.

Video Link


Creating formarray of formgroup objects in Angular

Suggested Videos
Part 17 - How to make angular custom validator reusable | Text | Slides
Part 18 - Angular reactive forms cross field validation | Text | Slides
Part 19 - Angular formarray example | Text | Slides

In this video we will discuss Creating a FormArray of FormGroup objects


If you are wondering, why are we doing this?

Well, this is preparation for dynamically creating FormGroups at runtime. Every time we click, "Add Skill" button on the "Employee Form" below, we want to dynamically generate a new set of skill related form fields. So in this video, we will do all the preparation required for that.


angular formarray of formgroup

Component Class Code :

constructor(private fb: FormBuilder) { }

ngOnInit() {
  this.employeeForm = this.fb.group({
    fullName: ['', [Validators.required]],
    contactPreference: ['email'],
    // Other Form Controls..
    // Create skills FormArray using the injected FormBuilder
    // class array() method. At the moment, in the created
    // FormArray we only have one FormGroup instance that is
    // returned by addSkillFormGroup() method
    skills: this.fb.array([
      this.addSkillFormGroup()
    ])
  });

  // Rest of the code
}

addSkillFormGroup(): FormGroup {
  return this.fb.group({
    skillName: ['', Validators.required],
    experienceInYears: ['', Validators.required],
    proficiency: ['', Validators.required]
  });
}

In the template, use the formArrayName directive to bind to the skills FormArray. Now the important point to keep in mind is, in the component class, we only have one FormGroup instance in the skills FormArray. That one FormGroup instance is present at index position ZERO in the FormArray. This is the reason we have set formGroupName="0".

HTML in the view template

<div class="well">
  <div formArrayName="skills">
    <div formGroupName="0">
      <!-- Skill Name Label & Form Control HTML
        Experience Label & Form Control HTML
        Proficiency Label & Form Control HTML -->
    </div>
  </div>
</div>

With the above 2 changes, the validation is broken. To fix it, modify the code in logValidationErrors() method as shown below.

logValidationErrors(group: FormGroup = this.employeeForm): void {
  Object.keys(group.controls).forEach((key: string) => {
    const abstractControl = group.get(key);

    this.formErrors[key] = '';
    if (abstractControl && !abstractControl.valid &&
      (abstractControl.touched || abstractControl.dirty)) {
      const messages = this.validationMessages[key];

      for (const errorKey in abstractControl.errors) {
        if (errorKey) {
          this.formErrors[key] += messages[errorKey] + ' ';
        }
      }
    }

    if (abstractControl instanceof FormGroup) {
      this.logValidationErrors(abstractControl);
    }

    // We need this additional check to get to the FormGroup
    // in the FormArray and then recursively call this
    // logValidationErrors() method to fix the broken validation
    if (abstractControl instanceof FormArray) {
      for (const control of abstractControl.controls) {
        if (control instanceof FormGroup) {
          this.logValidationErrors(control);
        }
      }
    }
  });
}

Next video : We will discuss generating skill realted FormGroups and FormControls dynamically at runtime.

Video Link


Angular dynamic forms tutorial

Suggested Videos
Part 18 - Angular reactive forms cross field validation | Text | Slides
Part 19 - Angular formarray example | Text | Slides
Part 20 - Creating formarray of formgroup objects in Angular | Text | Slides

In this video, we will discuss generating FormGroups and FormControls dynamically at runtime


Here is what we want to do. Every time we click "Add Skill" button we want to generate another set of skill related form controls (i.e Skill, Experience & Proficiency).


angular dynamic forms tutorial

This is continuation to our previous video, Part 20. Please watch Part 20 from Angular 6 tutorial before proceeding.

Step 1 : Include Add Skill button

Place the following HTML inside the <div> element with class well. Notice the click event is bound to addSkillButtonClick() method. We will create this method in the component class next.

<div class="form-group">
  <div class="col-md-offset-2 col-md-4">
    <button type="button" class="btn btn-primary" (click)="addSkillButtonClick()">
      Add Skill
    </button>
  </div>
</div>

Step 2 : Include addSkillButtonClick() method in the component class
  • From the root FormGroup "employeeForm" get a reference to the skills FormArray. Notice we have passed the name of the FormArray (skills) as a parameter to the get() method.
  • The get() method returns the FormArray as an AbstractControl. We know it's a FormArray so we are type casting it to FormArray.
  • We are then calling the push() method of the FormArray to push a new FormGroup into the FormArray
  • The push() method calls addSkillFormGroup() method which returns an instance of the FormGroup with the 3 skill related form controls (skill, experience & proficiency)

addSkillButtonClick(): void {
  (<FormArray>this.employeeForm.get('skills')).push(this.addSkillFormGroup());
}

Step 3 : Loop over "skills" FormArray to dynamically generate the HTML input elements.
  • Notice we are using *ngFor structural directive to loop over the "skills" FormArray
  • For each FormGroup in the FormArray, the respective HTML input elements (skill, experience & proficiency) will be generated
  • We are also binding the formGroupName directive to the loop variable i
  • Since we are binding to a variable do not forget to use square brackets around [formGroupName] directive, otherwise you will get a run-time error - Cannot find control with path: 'skills -> i'
<div formArrayName="skills"
     *ngFor="let skill of employeeForm.get('skills').controls; let i = index">
  <div [formGroupName]="i">
      <!-- Skill Name Label & Form Control HTML
      Experience Label & Form Control HTML
      Proficiency Label & Form Control HTML -->
  </div>
</div>

At the moment there are several problems with the dynamically generated HTML input elements

  • The dynamically generated HTML input elements have the same id. For example, all the "skillName" textboxes have the same id "skillName". Not only the id, even the for attribute value of the labels is also the same.
  • As a result when we click on a label of an input element, the wrong textbox receives focus.
  • Also, the validation is broken.
  • We will discuss fixing these issues in our next upcoming videos.
Video Link


Generate unique id value for dynamically created form controls in angular

Suggested Videos
Part 19 - Angular formarray example | Text | Slides
Part 20 - Creating formarray of formgroup objects in Angular | Text | Slides
Part 21 - Angular dynamic forms tutorial | Text | Slides

In this video we will discuss how to generate unique id value for the dynamically created form controls in Angular.


If you are wondering, why is there a need to generate unique id values

Well, first of all, IDs on an HTML page are meant to be unique. Having duplication IDs is a terrible idea. Although it may work in some cases, it is semantically incorrect to do so.

In our case the application behaves erratically, because of duplicate element IDs. When we click on a label, we expect it's corresponding input element to receive focus, but, in our case, a different element receives focus. To fix this we have to generate unique ID values for the input elements.


<div formArrayName="skills"
      *ngFor="let skill of employeeForm.get('skills').controls; let i = index">
  <div [formGroupName]="i">

    <div class="form-group" [ngClass]="{'has-error': formErrors.skillName}">
      <label class="col-sm-2 control-label" attr.for="{{'skillName'+i}}">
        Skill
      </label>
      <div class="col-sm-4">
        <input type="text" class="form-control" id="{{'skillName'+i}}"
                formControlName="skillName" (blur)="logValidationErrors()"
                placeholder="C#, Java, Angular etc...">
        <span class="help-block" *ngIf="formErrors.skillName">
          {{formErrors.skillName}}
        </span>
      </div>
    </div>

    <!-- Experience Label & Form Control HTML
         Proficiency Label & Form Control HTML -->

  </div>
</div>


Code Explanation
  • *ngFor directive on the formArrayName <div> element loops through all the dynamically generated form groups.
  • The variable i value will be ZERO when we are looping through the first FormGroup in the skills form array.
  • The value of i will be ONE, for the second FormGroup, TWO for the third FormGroup so on and so forth.
  • Notice the id attribute of the skillName textbox. We are dynamically computing it's ID, by appening i variable value to the string skillName
    id="{{'skillName'+i}}"
  • This will generate an ID of skillName0 for the first skillName input element, ID of skillName1 for the second skillName input element, so on so forth, to ensure unique ID values are assigned to all the dynamically generated skillName input elements.
  • In the above expression we are using interpolation. We could also achieve the same using property binding syntax instead of interpolation.
    [id]="'skillName'+i"
  • If you are new to property binding, please check out our following video on property binding in Angular
  • Also notice, we are dynamically setting the value of the for attribute of the Skill label.
    attr.for="{{'skillName'+i}}"
  • Since the for attribute does not have a corresponding DOM property, we are using Angular's attribute binding.
  • If you are new to attribute binding, please check out our following video on Attribute binding in Angular
  • With the attribute binding, we are using interpolation. We could also achieve the same using property binding syntax.
    [attr.for]="'skillName'+i"
Similarly set a unique value for the experienceInYears input element ID and it's associated label for attribute.

<div class="form-group" [ngClass]="{'has-error': formErrors.experienceInYears}">
  <label class="col-sm-2 control-label" attr.for="{{'experienceInYears'+i}}">
    Experience
  </label>
  <div class="col-sm-4">
    <input type="text" class="form-control" id="{{'experienceInYears'+i}}"
            formControlName="experienceInYears"
            placeholder="In Years" (blur)="logValidationErrors()">
    <span class="help-block" *ngIf="formErrors.experienceInYears">
      {{formErrors.experienceInYears}}
    </span>
  </div>
</div>

Video Link


Angular dynamic forms validation

Suggested Videos
Part 20 - Creating formarray of formgroup objects in Angular | Text | Slides
Part 21 - Angular dynamic forms tutorial | Text | Slides
Part 22 - Generate unique id value for dynamically created form controls in angular | Text | Slides

In this video we will discuss validating dynamically generated form controls.

Modify the skillName form control HTML as shown below. 




<div formArrayName="skills"
    *ngFor="let skill of employeeForm.get('skills').controls; let i = index">

  <div [formGroupName]="i">

    <div class="form-group" [ngClass]="{'has-error':
          skill.get('skillName').invalid && skill.get('skillName').touched}">
      <label class="col-sm-2 control-label" [attr.for]="'skillName'+i">
        Skill
      </label>
      <div class="col-sm-4">
        <input type="text" class="form-control" [id]="'skillName'+i"
                formControlName="skillName" placeholder="C#, Java, Angular etc...">
        <span class="help-block" *ngIf="skill.get('skillName').errors?.required &&
                                              skill.get('skillName').touched">
          Skill Name is required
        </span>
      </div>
    </div>

  </div>
</div>

Notice, we are using the loop variable skill, to check if the dynamically generated skillName form control is invalid and touched. If so, the has-error bootstrap style class is applied. To get to the skillName form control in the skill FormGroup, we are using the get() method on the FormGroup and passing it the form control name.

[ngClass]="{'has-error': skill.get('skillName').invalid &&
                         skill.get('skillName').touched}"

To get to the skillName form control in the skill FormGroup, we can also use controls property on the FormGroup and then the skillName form control.

[ngClass]="{'has-error': skill.controls.skillName.invalid &&
                          skill.controls.skillName.touched}"

Even here, we are using the loop variable skill, to check if the dynamically generated skillName form control has failed required validation and touched. If so, the <span> element displays the validation error, otherwise hides it. 

<span class="help-block" *ngIf="skill.get('skillName').errors?.required &&
                                      skill.get('skillName').touched">
  Skill Name is required
</span>

Make sure to use the safe navigation operator between errors and required properties. This is because, when the skillName form control does not have any validation errors, the errors property will be null and trying to check for required key on a null object will result in Cannot read property 'required' of null error.

skill.get('skillName').errors?.required

Make similar changes on experienceInYears and proficiency form controls.

<div class="form-group" [ngClass]="{'has-error':
skill.get('experienceInYears').invalid && skill.get('experienceInYears').touched}">
  <label class="col-sm-2 control-label" [attr.for]="'experienceInYears'+i">
    Experience
  </label>
  <div class="col-sm-4">
    <input type="text" class="form-control" [id]="'experienceInYears'+i"
            formControlName="experienceInYears" placeholder="In Years">
    <span class="help-block" *ngIf="skill.get('experienceInYears').errors?.required &&
                                    skill.get('experienceInYears').touched">
      Experience is required
    </span>
  </div>
</div>

<div class="form-group" [ngClass]="{'has-error':
skill.get('proficiency').invalid && skill.get('proficiency').touched}">
  <label class="col-sm-2 control-label">Proficiency</label>
  <div class="col-sm-8">
    <label class="radio-inline">
      <input type="radio" value="beginner" formControlName="proficiency">Beginner
    </label>
    <label class="radio-inline">
      <input type="radio" value="intermediate" formControlName="proficiency">Intermediate
    </label>
    <label class="radio-inline">
      <input type="radio" value="advanced" formControlName="proficiency">Advanced
    </label>
    <span class="help-block" *ngIf="skill.get('proficiency').errors?.required &&
                                    skill.get('proficiency').touched">
      Proficiency is required
    </span>
  </div>
</div>

All the skill form controls validation messages are in the template. So delete the validation messages from the validationMessages object in the component class.

validationMessages = {
  'fullName': {
    'required': 'Full Name is required.',
    'minlength': 'Full Name must be greater than 2 characters.',
    'maxlength': 'Full Name must be less than 10 characters.'
  },
  'email': {
    'required': 'Email is required.',
    'emailDomain': 'Email domian should be dell.com'
  },
  'confirmEmail': {
    'required': 'Confirm Email is required.',
  },
  'emailGroup': {
    'emailMismatch': 'Email and Confirm Email do not match',
  },
  'phone': {
    'required': 'Phone is required.'
  },
  // 'skillName': {
  //   'required': 'Skill Name is required.',
  // },
  // 'experienceInYears': {
  //   'required': 'Experience is required.',
  // },
  // 'proficiency': {
  //   'required': 'Proficiency is required.',
  // },
};

On the formErrors object also, delete the skill related properties. In fact, we do not need any of the properties on the formErrors object, as they will be dynamically added when the corresponding form control fails validation. Notice, I have commented all the properties on the formErrors object.

formErrors = {
  // 'fullName': '',
  // 'email': '',
  // 'confirmEmail': '',
  // 'emailGroup': '',
  // 'phone': '',
  // 'skillName': '',
  // 'experienceInYears': '',
  // 'proficiency': ''
};

Since the validation messages for the skill form controls are in the template, we do not have to loop through the skill form groups in the form array. So I have commented the block of code that loops through the FormArray.

logValidationErrors(group: FormGroup = this.employeeForm): void {
  Object.keys(group.controls).forEach((key: string) => {
    const abstractControl = group.get(key);

    this.formErrors[key] = '';
    if (abstractControl && !abstractControl.valid &&
      (abstractControl.touched || abstractControl.dirty)) {
      const messages = this.validationMessages[key];

      for (const errorKey in abstractControl.errors) {
        if (errorKey) {
          this.formErrors[key] += messages[errorKey] + ' ';
        }
      }
    }

    if (abstractControl instanceof FormGroup) {
      this.logValidationErrors(abstractControl);
    }

    // if (abstractControl instanceof FormArray) {
    //   for (const control of abstractControl.controls) {
    //     if (control instanceof FormGroup) {
    //       this.logValidationErrors(control);
    //     }
    //   }
    // }
  });
}

Video Link


Angular formarray validation

Suggested Videos
Part 21 - Angular dynamic forms tutorial | Text | Slides
Part 22 - Generate unique id value for dynamically created form controls in angular | Text | Slides
Part 23 - Angular dynamic forms validation | Text | Slides

In this video we will discuss validating FormArray in Angular.

  • A FormArray can contain form controls, form groups or nested form arrays.
  • In our case, the "skills" form array, contains form groups. Each form group contains, 3 form controls. angular formarray invalid
  • If all the 3 form controls are valid, then the form group is valid
  • If all the form groups are valid, then the form array is valid.
  • Even if a single form control in a form group is invalid, then the form array is invalid.

Here is what we want to do. Until, all the skill related form controls are properly filled and valid, we want to keep "Add Skill" button disabled

angular formarray validation

This is very easy to achieve. We already know, even if a single form control is invalid, the entire form array is invalid. So to keep the "Add Skill" button disabled, bind the button disabled property to "skills" form array invalid property as shown below.

<button type="button" class="btn btn-primary"
        (click)="addSkillButtonClick()"
        [disabled]="employeeForm.get('skills').invalid">
  Add Skill
</button>

While we are here, let's also include an <hr> element to separate each skills form group.

angular formarray disable

We want the <hr> element to be generated, only if we have more than 1 skills form group, hence we have bound *ngIf directive on the <hr> element to i>0

<div formArrayName="skills"
     *ngFor="let skill of employeeForm.get('skills').controls; let i = index">
  <hr *ngIf="i>0">
  <div [formGroupName]="i">

In the CSS file, include the following style for the <hr> element

hr {
    border: 1px solid silver;
}

Video Link


Remove dynamically created form controls in angular

Suggested Videos
Part 22 - Generate unique id value for dynamically created form controls in angular | Text | Slides
Part 23 - Angular dynamic forms validation | Text | Slides
Part 24 - Angular formarray validation | Text | Slides

In this video we will discuss how to remove dynamically generated form controls. Let us understand this with an example.


At the moment we have just one set of skill related form controls (skillName, experienceInYears & proficiency)

remove dynamically created form controls in angular


As soon as, we add another set of skill related form controls, a button with a RED cross should appear next to each skill form group.

angular remove dynamic formcontrol from formgroup

When the button is clicked, the associated set of skill form controls should be removed.

Here is the  HTML for the DELETE button

<div class="col-sm-6" *ngIf="employeeForm.get('skills').length>1">
  <button type="button" class="btn btn-danger btn-sm pull-right"
          title="Delete Skill" (click)="removeSkillButtonClick(i)">
    <span class="glyphicon glyphicon-remove"></span>
  </button>
</div>

Code Explanation :

The following *ngIf expression ensures, the DELETE SKILL button is only displayed if we have more than one skill FormGroup in the skills FormArray

*ngIf="employeeForm.get('skills').length>1"

When the button is clicked, removeSkillButtonClick(i) method is called. Notice we are passing the loop variable i to the method. This is the index of the FormGroup that we want to remove from the skills FormArray

(click)="removeSkillButtonClick(i)"

The title attribute on the button, displays "Delete Skill" tooltip when you hover the mouse pointer over the button

title="Delete Skill"

To display the red cross on the button, we are using Bootstrap glyphicon and glyphicon-remove classes.

<span class="glyphicon glyphicon-remove"></span>

If you do not want to display the DELETE button for the first "skills" form group

how to delete dynamic formgroups in angular

Then use the following ngIf expression on the <div> element that contains the "DELETE" button. This will ensure that the DELETE button will only be displayed for all the dynamically generated SKILL form groups except the first one.

<div class="col-sm-6" *ngIf="i>0">

Include the following method in the component class. 

removeSkillButtonClick(skillGroupIndex: number): void {
  (<FormArray>this.employeeForm.get('skills')).removeAt(skillGroupIndex);
}

Code Explanation
  • Notice we are using the get() on the root form group (employeeForm) and passing it the name of our skills FormArray. 
  • The get() method returns the FormArray as an abstract control
  • To be able to use removeAt() method of the FormArray class, we are type casting the AbstractControl type to FormArray using the type caste operator <FormArray>
  • To the removeAt() method we pass the index of the skill FormGroup we want to remove from the skills FormArray
Video Link


rxjs operators in angular services

Suggested Videos
Part 23 - Angular dynamic forms validation | Text | Slides
Part 24 - Angular formarray validation | Text | Slides
Part 25 - Remove dynamically created form controls in angular | Text | Slides

Angular 6 uses rxjs 6. You can verify this by looking at package.json file in your Angular 6 project. In this video we will discuss using rxjs 6 operators in Angular 6 services.


In the project that we have been working with so far in this video tutorial, we need to do some ground work before we we can create an angular service. 


Creating a fake online REST API

First let's create a fake online REST API. For this we are going to use JSON-Server. We discussed what REST API is and using JSON-server in Part 63 of Angular CRUD tutorial.

The following is the JSON Server Github page 
https://github.com/typicode/json-server

Execute the following NPM command to install JSON server

npm install -g json-server 

Create db.json file in the root project folder. Copy and paste the following JSON data in the file.

{
    "employees": [
        {
            "id": 1,
            "fullName": "Mark",
            "contactPreference": "email",
            "email": "mark@email.com",
            "phone": "5641238971",
            "skills": [
                {
                    "skillName": "C#",
                    "experienceInYears": 1,
                    "proficiency": "beginner"
                },
                {
                    "skillName": "Java",
                    "experienceInYears": 2,
                    "proficiency": "intermediate"
                }
            ]
        },
        {
            "id": 2,
            "fullName": "John",
            "contactPreference": "phone",
            "email": "john@email.com",
            "phone": "3242138971",
            "skills": [
                {
                    "skillName": "Angular",
                    "experienceInYears": 2,
                    "proficiency": "beginner"
                },
                {
                    "skillName": "HTML",
                    "experienceInYears": 2,
                    "proficiency": "intermediate"
                },
                {
                    "skillName": "LINQ",
                    "experienceInYears": 3,
                    "proficiency": "advanced"
                }
            ]
        }
    ]
}

Execute the following command to start the server

json-server --watch db.json

At this point, fire up the browser and navigate to http://localhost:3000/employees/ to see the list of all employees along with their skills. You can test this REST API using a tool like fiddler. 

Creating the required interfaces to represent Employee and Skill types

Add a file in the employee folder with name ISkill.ts. Copy and paste the following code.

export interface ISkill {
    skillName: string;
    experienceInYears: number;
    proficiency: string;
}

Add a file in the employee folder with name IEmployee.ts. Copy and paste the following code.

import { ISkill } from './ISkill';

export interface IEmployee {
    id: number;
    fullName: string;
    email: string;
    phone?: number;
    contactPreference: string;
    skills: ISkill[];
}

Creating Angular Service

Add a file in the employee folder with name employee.service.ts. Copy and paste the following code.

import { Injectable } from '@angular/core';
import { IEmployee } from './IEmployee';
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';

import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Injectable()
export class EmployeeService {
    baseUrl = 'http://localhost:3000/employees';
    constructor(private httpClient: HttpClient) {
    }

    getEmployees(): Observable<IEmployee[]> {
        return this.httpClient.get<IEmployee[]>(this.baseUrl)
            .pipe(catchError(this.handleError));
    }

    private handleError(errorResponse: HttpErrorResponse) {
        if (errorResponse.error instanceof ErrorEvent) {
            console.error('Client Side Error :', errorResponse.error.message);
        } else {
            console.error('Server Side Error :', errorResponse);
        }
        return throwError('There is a problem with the service. We are notified & working on it. Please try again later.');
    }

    getEmployee(id: number): Observable<IEmployee> {
        return this.httpClient.get<IEmployee>(`${this.baseUrl}/${id}`)
            .pipe(catchError(this.handleError));
    }

    addEmployee(employee: IEmployee): Observable<IEmployee> {
        return this.httpClient.post<IEmployee>(this.baseUrl, employee, {
            headers: new HttpHeaders({
                'Content-Type': 'application/json'
            })
        })
        .pipe(catchError(this.handleError));
    }

    updateEmployee(employee: IEmployee): Observable<void> {
        return this.httpClient.put<void>(`${this.baseUrl}/${employee.id}`, employee, {
            headers: new HttpHeaders({
                'Content-Type': 'application/json'
            })
        })
            .pipe(catchError(this.handleError));
    }

    deleteEmployee(id: number): Observable<void> {
        return this.httpClient.delete<void>(`${this.baseUrl}/${id}`)
            .pipe(catchError(this.handleError));
    }
}

RxJS 5 vs 6

An Angular 6 project, by default uses RxJS version 6. RxJS 6 has some breaking changes compared to RxJS 5.5 and older versions.

The way we import some of the classes like Observable and Subject has changed in RxJS 6.

In RxJS 5, we import Observable and Subject classes as shown below.

import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';

In RxJS 6, this has changed to

import { Observable, Subject } from 'rxjs';

Similarly, the way we import operators also changed in RxJS 6. To import catchError operator in RxJS 5, we use the following

import { catchError } from 'rxjs/operators/catchError';

In RxJS 6, it has changed to the following

import { catchError } from 'rxjs/operators';

In RxJS 6, we import all the operators from 'rxjs/operators'

import { map, delay, catchError } from 'rxjs/operators';

Many classes like ArrayObservable, EmptyObservable, ErrorObservable etc are also removed from v6, in favour of existing or new operators that perform the same operations.

For example, in v5 to create an ErrorObservable we might use one of the following

new ErrorObservable('Your error message');

OR

ErrorObservable.create('Your error message');

In v6, we use throwError() function to achieve this. 

return throwError('Your error message');

How do I know, I have to use throwError() function instead of ErrorObservable class. Well, the following GitHub article contains all the differences between RxJS v5.x and v6. A quick search (CTRL + F) on the page for ErrorObservable shows, it has been removed in favour of throwError() function.
https://github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/migration.md

in v6, import throwError function from rxjs. Since ErrorObservable class is replaced by throwError function, we import it the same way we import other classes like Observable and Subject from rxjs.

import { Observable, throwError } from 'rxjs';

Implementing ListEmployeesComponent : While we are here, let's implement ListEmployeesComponent

We want this component to display all employee details as shown below.

angular list component example

Copy and paste the following HTML in list-employees.component.html

<div class="table-responsive">
  <table class="table table-bordered" *ngIf="employees && employees.length">
    <thead>
      <tr class="bg-primary">
        <th>Name</th>
        <th>Email</th>
        <th>Phone</th>
        <th>Contact Preference</th>
        <th>Action</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let employee of employees">
        <td>{{ employee.fullName }}</td>
        <td>{{ employee.email }}</td>
        <td>{{ employee.phone }}</td>
        <td>{{ employee.contactPreference }}</td>
        <td> <button class="btn btn-primary">Edit</button> </td>
      </tr>
    </tbody>
  </table>
</div>

Copy and paste the following code in list-employees.component.ts

import { Component, OnInit } from '@angular/core';
import { EmployeeService } from './employee.service';
import { IEmployee } from './IEmployee';

@Component({
  selector: 'app-list-employees',
  templateUrl: './list-employees.component.html',
  styleUrls: ['./list-employees.component.css']
})
export class ListEmployeesComponent implements OnInit {
  employees: IEmployee[];

  constructor(private _employeeService: EmployeeService) { }

  ngOnInit() {
    this._employeeService.getEmployees().subscribe(
      (employeeList) => this.employees = employeeList,
      (err) => console.log(err)
    );
  }

}

Changes in app.module.ts file

To be able to use EmployeeService in ListEmployeesComponent we have to register it. Since we want EmployeeService to be available across the entire application, Let's register it in the application root module AppModule.

Import EmployeeService and include it in the providers array of @NgModule decorator of AppModule. Employee service uses angular's HttpClient service. To be able to use this we have to import HttpClientModule in the AppModule and include it in the imports array.

import { EmployeeService } from './employee/employee.service';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent,
    CreateEmployeeComponent,
    ListEmployeesComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    ReactiveFormsModule
  ],
  providers: [EmployeeService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Video Link


Angular reactive forms edit example

Suggested Videos
Part 24 - Angular formarray validation | Text | Slides
Part 25 - Remove dynamically created form controls in angular | Text | Slides
Part 26 - RxJS operators in angular services | Text | Slides

In this video we will discuss Implementing EDIT operation in a reactive form. We will use Create Employee Form for both creating a new employee as well as editing an existing employee details.


Changes in app-routing.module.ts
  • Include a new route for editing an existing employee details in app-routing.module.ts
  • We will use "create" route to create a new employee. 
  • The new "edit" route will be for editing an existing employee details. 
  • Notice to the "edit" route we are passing the id of the employee we want to edit.
const appRoutes: Routes = [
  { path: 'list', component: ListEmployeesComponent },
  { path: 'create', component: CreateEmployeeComponent },
  { path: 'edit/:id', component: CreateEmployeeComponent },
  { path: '', redirectTo: '/list', pathMatch: 'full' }
];


Changes in list-employees.component.html : Include click event binding on the Edit button.

<td>
  <button class="btn btn-primary" (click)="editButtonClick(employee.id)">
    Edit
  </button>
</td>

Changes in list-employees.component.ts : Import Angular Router

import { Router } from '@angular/router';

Inject it into the component class using the constructor

constructor(private _employeeService: EmployeeService,
            private _router: Router) { }

Include editButtonClick() event handler method in the component class. When the Edit button is clicked, the user will be redirected to the "edit" route, passing it the id of the employee we want to edit.

editButtonClick(employeeId: number) {
  this._router.navigate(['/edit', employeeId]);
}

Changes in create-employee.component.ts to support editing an existing employee

Import ActivatedRoute, EmployeeService, IEmployee and ISkill types

import { ActivatedRoute } from '@angular/router';
import { EmployeeService } from './employee.service';
import { IEmployee } from './IEmployee';
import { ISkill } from './ISkill';

Inject ActivatedRoute and EmployeeService into the component class using the constructor

constructor(private fb: FormBuilder,
            private route: ActivatedRoute,
            private employeeService: EmployeeService) { }

In ngOnInit(), read the id route parameter value. If it is truthy i.e if the id value exists on the route, then call the geEmployee(id) method passing it the employee id. 

Once the employee data is retrieved and mapped to IEmployee type, it is then passed to editEmployee(employee: IEmployee) method. 

ngOnInit() {
  // Other existing code...

  this.route.paramMap.subscribe(params => {
    const empId = +params.get('id');
    if (empId) {
      this.getEmployee(empId);
    }
  });
}

getEmployee(id: number) method calls the EmployeeService and retrieves the existing employee details.

getEmployee(id: number) {
  this.employeeService.getEmployee(id)
    .subscribe(
      (employee: IEmployee) => this.editEmployee(employee),
      (err: any) => console.log(err)
    );
}

The following editEmployee() method updates the form controls with the employee data, so the data is displayed on the form and the end user can edit it.

Notice we are using patchValue() method, to update the form controls with the employee data retrieved from the server.

editEmployee(employee: IEmployee) {
  this.employeeForm.patchValue({
    fullName: employee.fullName,
    contactPreference: employee.contactPreference,
    emailGroup: {
      email: employee.email,
      confirmEmail: employee.email
    },
    phone: employee.phone
  });
}

At the moment, we have 3 minor bugs when editing an existing employee.

Save button not disabled if the form is invalid : To disable the Save button bind disabled property of the button to the invalid property of the employeeForm

<button class="btn btn-primary" type="submit" [disabled]="employeeForm.invalid">
  Save
</button>

We have a custom email validator attached to the email form control. This custom email validator fails validation if the email domain is not dell.com

However, the validation error message is not displayed until the form control is touched or dirty. As we are editing the existing employee details, it makes more sense to display the validation errors if the data is invalid rather than waiting until the email form control is touched or dirty

To fix this, modify logValidationErrors() function as shown below.

logValidationErrors(group: FormGroup = this.employeeForm): void {
  Object.keys(group.controls).forEach((key: string) => {
    const abstractControl = group.get(key);

    this.formErrors[key] = '';
    // abstractControl.value !== '' (This condition ensures if there is a value in the
    // form control and it is not valid, then display the validation error)
    if (abstractControl && !abstractControl.valid &&
        (abstractControl.touched || abstractControl.dirty || abstractControl.value !== '')) {
      const messages = this.validationMessages[key];

      for (const errorKey in abstractControl.errors) {
        if (errorKey) {
          this.formErrors[key] += messages[errorKey] + ' ';
        }
      }
    }

    if (abstractControl instanceof FormGroup) {
      this.logValidationErrors(abstractControl);
    }
  });
}

Similarly, if email and confirm email are not equal, the validation error is not displayed until the confirm email form control is dirty. To fix this include the following condition in matchEmail() function.

confirmEmailControl.value === ''

Here is the matchEmail() function with the above condition included.

function matchEmail(group: AbstractControl): { [key: string]: any } | null {
  const emailControl = group.get('email');
  const confirmEmailControl = group.get('confirmEmail');
  // If confirm email control value is not an empty string, and if the value
  // does not match with email control value, then the validation fails
  if (emailControl.value === confirmEmailControl.value
    || (confirmEmailControl.pristine && confirmEmailControl.value === '')) {
    return null;
  } else {
    return { 'emailMismatch': true };
  }
}

At the moment, the skills form array is not populated with the employees existing skills. We will discuss how to do this in our next video.
Video Link


Angular populate formarray

Suggested Videos
Part 25 - Remove dynamically created form controls in angular | Text | Slides
Part 26 - RxJS operators in angular services | Text | Slides
Part 27 - Angular reactive forms edit example | Text | Slides

In this video we will discuss how to populate angular formarray with existing data. This is continuation to Part 27. Please watch Part 27 from Angular 6 tutorial before proceeding.


We want to populate the skills FormArray, with the existing skills an employee has.

For example, consider the following data of an existing employee.


{
  "id": 2,
  "fullName": "John",
  "contactPreference": "phone",
  "email": "john@email.com",
  "phone": "3242138971",
  "skills": [
    {
      "skillName": "Angular",
      "experienceInYears": 2,
      "proficiency": "beginner"
    },
    {
      "skillName": "HTML",
      "experienceInYears": 2,
      "proficiency": "intermediate"
    },
    {
      "skillName": "LINQ",
      "experienceInYears": 3,
      "proficiency": "advanced"
    }
  ]
}

When we load this data on a form to edit this employee details, we want to populate skills FormArray as shown below.

angular populate formarray

To achieve this modify editEmployee() method in create-employee.component.ts as shown below.

Notice we are using setControl() method to replace the skills FormArray with the FormArray that setExistingSkills() method returns.

editEmployee(employee: IEmployee) {
  this.employeeForm.patchValue({
    fullName: employee.fullName,
    contactPreference: employee.contactPreference,
    emailGroup: {
      email: employee.email,
      confirmEmail: employee.email
    },
    phone: employee.phone
  });

  this.employeeForm.setControl('skills', this.setExistingSkills(employee.skills));
}

setExistingSkills() method
  • loops through each skill object of an employee
  • Creates a FormGroup with 3 form controls (skillName, experienceInYears, proficiency)
  • Pushes the FormGroup into the FormArray
  • Finally, this FormArray with the existing skills of the employee is returned
setExistingSkills(skillSets: ISkill[]): FormArray {
  const formArray = new FormArray([]);
  skillSets.forEach(s => {
    formArray.push(this.fb.group({
      skillName: s.skillName,
      experienceInYears: s.experienceInYears,
      proficiency: s.proficiency
    }));
  });

  return formArray;
}

Important - Programmatically changing a formarray in angular does not change dirty state : At this point, if you remove one of the skill groups from the FormArray by clicking the "Delete Skill" button, notice the dirty and touched state of the form is still false

This is because, the state properties like dirty, touched etc are designed to indicate whether a user has interacted with the form. 

By default, programmatic change to value of a form control will not flip the value of these properties. However, in some cases you may need to mark form controls, form groups and form arrays as touched, dirty etc. In such cases you can explicitly do so by calling markAsDirty() and markAsTouched() methods.

In our case, when a SKILL form group is removed from the FormArray we want to mark the formArray as touched and dirty. To achieve this, we are using markAsDirty() and markAsTouched() methods.

removeSkillButtonClick(skillGroupIndex: number): void {
  const skillsFormArray = <FormArray>this.employeeForm.get('skills');
  skillsFormArray.removeAt(skillGroupIndex);
  skillsFormArray.markAsDirty();
  skillsFormArray.markAsTouched();
}

Video Link


Angular reactive forms put example

Suggested Videos
Part 26 - RxJS operators in angular services | Text | Slides
Part 27 - Angular reactive forms edit example | Text | Slides
Part 28 - Angular populate formarray | Text | Slides

In this video we will discuss harvesting data from a reactive form and issuing a PUT request to the REST API so the data is updated on the server.


At the component class level, include a property of type IEmployee. We will use this property to hold the employee data loaded from the server for editing.

employee: IEmployee;


Modify getEmployee(id: number) method to store the employee object returned by the REST API

getEmployee(id: number) {
  this.employeeService.getEmployee(id)
    .subscribe(
      (employee: IEmployee) => {
        // Store the employee object returned by the
        // REST API in the employee property
        this.employee = employee;
        this.editEmployee(employee);
      },
      (err: any) => console.log(err)
    );
}

Modify onSubmit() method as shown below.

onSubmit(): void {
  this.mapFormValuesToEmployeeModel();
  this.employeeService.updateEmployee(this.employee).subscribe(
    () => this.router.navigate(['list']),
    (err: any) => console.log(err)
  );
}

Also include the following mapFormValuesToEmployeeModel() method

mapFormValuesToEmployeeModel() {
  this.employee.fullName = this.employeeForm.value.fullName;
  this.employee.contactPreference = this.employeeForm.value.contactPreference;
  this.employee.email = this.employeeForm.value.emailGroup.email;
  this.employee.phone = this.employeeForm.value.phone;
  this.employee.skills = this.employeeForm.value.skills;
}

Code explanation : 

In the view template we have ngSubmit event bound to onSubmit() method

<form [formGroup]="employeeForm" (ngSubmit)="onSubmit()" class="form-horizontal">

So this method onSubmit(), is called when the employee form is submitted

mapFormValuesToEmployeeModel() method copies the edited values into the employee object

At this point, you may be thinking can't I simply type cast employeeForm.value to IEmployee type. 

this.employee = <IEmployee>this.employeeForm.value;

No, we can't do this because, the shape of employeeForm.value does not match with the shape of IEmployee

In employeeForm.value, we do not have id property. Also, email and conifrmEmail properties are present in a nested FormGroup called emailGroup in the employeeForm, where as in the IEmployee interface we do not have such an email group property. We only have email property on th IEmployee interface. confirmEmail form control in the employeeForm is only there for validation. We do not need to save it on the server.

Another approach is to use Object.assign() method as shown below.

this.employee = Object.assign({}, this.employee, this.employeeForm.value);

But this approach also will not work for us, because the employeeForm.value has an additional emailGroup property but not on the IEmploye interface. 

Hence, we need mapFormValuesToEmployeeModel() method to manually copy the edited values into the employee object so it could be saved to the 

The updateEmployee() method of Angular EmployeeService issues a PUT request to the server side REST API. Here is the updateEmployee() method for your reference

updateEmployee(employee: IEmployee): Observable<void> {
    return this.httpClient.put<void>(`${this.baseUrl}/${employee.id}`, employee, {
        headers: new HttpHeaders({
            'Content-Type': 'application/json'
        })
    })
        .pipe(catchError(this.handleError));
}

When the call to the REST API completes successfully, navigate the user to the list route

Angular Router service is required to navigate the user to the list route. So, please make sure to import and inject Angular Router service into the component class.

import { Router } from '@angular/router';


constructor(private fb: FormBuilder,
  private route: ActivatedRoute,
  private employeeService: EmployeeService,
  private router: Router) { }

At this point when you click the save button, the edited data should be saved and redirected to list route. You can see the saved changes in db.json file.

Video Link


Angular reactive forms post example

Suggested Videos
Part 27 - Angular reactive forms edit example | Text | Slides
Part 28 - Angular populate formarray | Text | Slides
Part 29 - Angular reactive forms put example | Text | Slides

In this video we will discuss collecting data from a reactive form and issuing a POST request to the REST API so the data is created on the server.


If we get to the CreateEmployeeComponent and in the route if we do not have ID parameter, then we know we are creating a new employee and not editing an existing employee.


So modify the code block in ngOnInit() as shown below. Notice in the ELSE block, we are initialising a new empty Employee object.

this.route.paramMap.subscribe(params => {
  const empId = +params.get('id');
  if (empId) {
    this.getEmployee(empId);
  } else {
    this.employee = {
      id: null,
      fullName: '',
      contactPreference: '',
      email: '',
      phone: null,
      skills: []
    };
  }
});

Next, modify code in onSubmit() method as shown below.
  • Check if the id property on the employee object is truthy.
  • IF it is, then we know we are editing an existing employee, so call updateEmployee() of the EmployeeService which issues a PUT request to the REST API.
  • ELSE, we know we are creating a new employee. So in this case, call addEmployee() method of the EmployeeService which issues a POST request to the REST API.
onSubmit(): void {
  this.mapFormValuesToEmployeeModel();

  if (this.employee.id) {
    this.employeeService.updateEmployee(this.employee).subscribe(
      () => this.router.navigate(['list']),
      (err: any) => console.log(err)
    );
  } else {
    this.employeeService.addEmployee(this.employee).subscribe(
      () => this.router.navigate(['list']),
      (err: any) => console.log(err)
    );
  }
}

Here is the addEmployee() method of the EmployeeService for your reference.

addEmployee(employee: IEmployee): Observable<IEmployee> {
    return this.httpClient.post<IEmployee>(this.baseUrl, employee, {
        headers: new HttpHeaders({
            'Content-Type': 'application/json'
        })
    })
    .pipe(catchError(this.handleError));
}

At this point, you should be able to create a new employee as well as edit an existing employee. 

The only issue at the moment is, whether you are creating a new employee or editing an existing employee, the page title always shows "Create Employee"

When editing, we want the page title to be "Edit Employee" and when creating a new employee, we want the page title to be "Create Employee".

Here are the steps to achieve this

Step 1 : At the component class level, include pageTitle property


pageTitle: string;

Step 2 : Modify the code block in ngOnInit() to set the pageTitle property accordingly.

this.route.paramMap.subscribe(params => {
  const empId = +params.get('id');
  if (empId) {
    this.pageTitle = 'Edit Employee';
    this.getEmployee(empId);
  } else {
    this.pageTitle = 'Create Employee';
    this.employee = {
      id: null,
      fullName: '',
      contactPreference: '',
      email: '',
      phone: null,
      skills: []
    };
  }
});

Step 3 : Finally in the template, bind to the pageTitle property

<div class="panel-heading">
  <h3 class="panel-title">{{pageTitle}}</h3>
</div>

Video Link


Angular modules explained

Suggested Videos
Part 28 - Angular populate formarray | Text | Slides
Part 29 - Angular reactive forms put example | Text | Slides
Part 30 - Angular reactive forms post example | Text | Slides

In this video we will discuss, what are Angular modules and why we need them in an Angular project.


In simple terms an Angular Module is a class decorated with @NgModule decorator.


An Angular Module is a mechanism to group components, directives, pipes and services that are related to a feature area of an angular application.

For example, if you are building an application to manage employees, you might have the following features in your application.

Application Feature Description
Employee Feature Deals with creating, reading, updating and deleting employees
Login Feature Deals with login, logout, authenticate and authorize users
Report Feature Deals with generating employee reports like total number of employees by department, top 10 best employees etc

To group the components, directives, pipes and services related to a specific feature area, we create a module for each feature area. These modules are called feature modules.

In addition to feature modules, an Angular application also contains the following modules.

Module Type Description
Root Module Every Angular application has at least one module, the root module. By default, this root application module is called AppModule. We bootstrap this root module to launch the application. If the application that you are building is a simple application with a few components, then all you need is the root module. As the application starts to grow and become complex, in addition to the root module, we may add several feature modules. We then import these feature modules into the root module. We will discuss creating feature modules in our upcoming videos
Core Module The most important use of this module is to include the providers of http services. Services in Angular are usually singletons. So to ensure that, only one instance of a given service is created across the entire application, we include all our singleton service providers in the core module. In most cases, a CoreModule is a pure services module with no declarations. The core module is then imported into the root module (AppModule) only. CoreModule should never be imported in any other module. We will discuss creating a core module in our upcoming videos
Shared Module This module contains reusable components, directives, and pipes that we want to use across our application. The Shared module is then imported into specific Feature Modules as needed. The Shared module might also export the commonly used Angular modules like CommonModule, FormsModule etc. so they can be easily used across your application, without importing them in every Feature Module. We will discuss creating a shared module in our upcoming videos
Routing Modules An angular application may also have one or more routing modules for application level routes and feature module routes

What are the advantages of splitting an angular application into multiple Angular Modules

Well, there are several benefits of Angular Modules. 

Benefit Description
Organizing Angular
Application
First of all, Modules are a great way to organise an angular application. Every feature area is present in it's own feature module. All Shared pieces (like components, directives & pipes) are present in a Shared module. All Singleton services are present in a core module. As we clearly know what is present in each module, it's easier to understand, find and change code if required
Code Reuse Modules are great way to reuse code. For example, if you have components, directives or pipes that you want to reuse, you include them in a Shared module and import it into the module where you need them rather than duplicating code. Code duplication is just plain wrong, and results in unmaintainable and error prone code. We will discuss creating a Shared module and how it can help us reuse code in our upcoming videos
Code Maintenance Since Angular Modules promote code reuse and separation of concerns, they are essential for writing maintainable code in angular projects
Performance Another great reason to refactor your application into modules is performance. Angular modules can be loaded either eagerly when the application starts or lazily on demand when they are actually needed or in the background. Lazy loading angular modules can significantly boost the application start up time. We will discuss lazy loading modules in our upcoming videos

@NgModule Decorator

As we have already discussed an Angular module is a class that is decorated with @NgModule decorator. The @NgModule decorator has the following properties.
  • declarations
  • bootstrap
  • providers
  • imports
  • exports
We will discuss these properties in detail when we discuss creating Feature, Shared and Core modules in our upcoming videos.

In preparation for refactoring our application into multiple modules, let's create the following 2 components
  • HomeComponent 
  • PageNotFoundComponent
Use the following Angular CLI command to create the HomeComponent

ng g c home --flat

Use the following Angular CLI command to create the PageNotFoundComponent

ng g c page-not-found --flat

If you are new to Angular CLI, please check out our Angular CLI course at the following link.
https://www.youtube.com/playlist?list=PL6n9fhu94yhWUcq5Pc16uf8YKXoZ87Vh_

Copy and paste the following code in home.component.html

<div class="panel panel-primary">
  <div class="panel-heading">
    <h3 class="panel-title">Employee Management System</h3>
  </div>
  <div class="panel-body">
    <img src="../assets/images/Employees.jpg" class="img-responsive"/>
  </div>
</div>

Please note : Create images folder in the assets folder. Download the following image. Name it Employees.jpg and place it in the images folder.

Employees Image

Copy and paste the following code in page-not-found.component.html

<h1>
  The page you are looking for cannot be found.
</h1>

Include home and wild card routes in app-routing.module.ts

import { HomeComponent } from './home.component';
import { PageNotFoundComponent } from './page-not-found.component';

const appRoutes: Routes = [
  // home route
  { path: 'home', component: HomeComponent },
  { path: 'list', component: ListEmployeesComponent },
  { path: 'create', component: CreateEmployeeComponent },
  { path: 'edit/:id', component: CreateEmployeeComponent },
  // redirect to the home route if the client side route path is empty
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  // wild card route
  { path: '**', component: PageNotFoundComponent }
];

In the root component (app.component.html) include a menu item for the home route

<div class="container">
    <nav class="navbar navbar-default">
        <ul class="nav navbar-nav">
            <!-- Include this Home menu item for the home route-->
            <li>
                <a routerLinkActive="active" routerLink="home">Home</a>
            </li>
            <li>
                <a routerLinkActive="active" routerLink="list">List</a>
            </li>
            <li>
                <a routerLinkActive="active" routerLink="create">Create</a>
            </li>
        </ul>
    </nav>
    <router-outlet></router-outlet>
</div>

In our next video we will discuss refactoring our application to include employee feature module.

Video Link


Angular modules explained

Suggested Videos
Part 28 - Angular populate formarray | Text | Slides
Part 29 - Angular reactive forms put example | Text | Slides
Part 30 - Angular reactive forms post example | Text | Slides

In this video we will discuss, what are Angular modules and why we need them in an Angular project.


In simple terms an Angular Module is a class decorated with @NgModule decorator.


An Angular Module is a mechanism to group components, directives, pipes and services that are related to a feature area of an angular application.

For example, if you are building an application to manage employees, you might have the following features in your application.

Application Feature Description
Employee Feature Deals with creating, reading, updating and deleting employees
Login Feature Deals with login, logout, authenticate and authorize users
Report Feature Deals with generating employee reports like total number of employees by department, top 10 best employees etc

To group the components, directives, pipes and services related to a specific feature area, we create a module for each feature area. These modules are called feature modules.

In addition to feature modules, an Angular application also contains the following modules.

Module Type Description
Root Module Every Angular application has at least one module, the root module. By default, this root application module is called AppModule. We bootstrap this root module to launch the application. If the application that you are building is a simple application with a few components, then all you need is the root module. As the application starts to grow and become complex, in addition to the root module, we may add several feature modules. We then import these feature modules into the root module. We will discuss creating feature modules in our upcoming videos
Core Module The most important use of this module is to include the providers of http services. Services in Angular are usually singletons. So to ensure that, only one instance of a given service is created across the entire application, we include all our singleton service providers in the core module. In most cases, a CoreModule is a pure services module with no declarations. The core module is then imported into the root module (AppModule) only. CoreModule should never be imported in any other module. We will discuss creating a core module in our upcoming videos
Shared Module This module contains reusable components, directives, and pipes that we want to use across our application. The Shared module is then imported into specific Feature Modules as needed. The Shared module might also export the commonly used Angular modules like CommonModule, FormsModule etc. so they can be easily used across your application, without importing them in every Feature Module. We will discuss creating a shared module in our upcoming videos
Routing Modules An angular application may also have one or more routing modules for application level routes and feature module routes

What are the advantages of splitting an angular application into multiple Angular Modules

Well, there are several benefits of Angular Modules. 

Benefit Description
Organizing Angular
Application
First of all, Modules are a great way to organise an angular application. Every feature area is present in it's own feature module. All Shared pieces (like components, directives & pipes) are present in a Shared module. All Singleton services are present in a core module. As we clearly know what is present in each module, it's easier to understand, find and change code if required
Code Reuse Modules are great way to reuse code. For example, if you have components, directives or pipes that you want to reuse, you include them in a Shared module and import it into the module where you need them rather than duplicating code. Code duplication is just plain wrong, and results in unmaintainable and error prone code. We will discuss creating a Shared module and how it can help us reuse code in our upcoming videos
Code Maintenance Since Angular Modules promote code reuse and separation of concerns, they are essential for writing maintainable code in angular projects
Performance Another great reason to refactor your application into modules is performance. Angular modules can be loaded either eagerly when the application starts or lazily on demand when they are actually needed or in the background. Lazy loading angular modules can significantly boost the application start up time. We will discuss lazy loading modules in our upcoming videos

@NgModule Decorator

As we have already discussed an Angular module is a class that is decorated with @NgModule decorator. The @NgModule decorator has the following properties.
  • declarations
  • bootstrap
  • providers
  • imports
  • exports
We will discuss these properties in detail when we discuss creating Feature, Shared and Core modules in our upcoming videos.

In preparation for refactoring our application into multiple modules, let's create the following 2 components
  • HomeComponent 
  • PageNotFoundComponent
Use the following Angular CLI command to create the HomeComponent

ng g c home --flat

Use the following Angular CLI command to create the PageNotFoundComponent

ng g c page-not-found --flat

If you are new to Angular CLI, please check out our Angular CLI course at the following link.
https://www.youtube.com/playlist?list=PL6n9fhu94yhWUcq5Pc16uf8YKXoZ87Vh_

Copy and paste the following code in home.component.html

<div class="panel panel-primary">
  <div class="panel-heading">
    <h3 class="panel-title">Employee Management System</h3>
  </div>
  <div class="panel-body">
    <img src="../assets/images/Employees.jpg" class="img-responsive"/>
  </div>
</div>

Please note : Create images folder in the assets folder. Download the following image. Name it Employees.jpg and place it in the images folder.

Employees Image

Copy and paste the following code in page-not-found.component.html

<h1>
  The page you are looking for cannot be found.
</h1>

Include home and wild card routes in app-routing.module.ts

import { HomeComponent } from './home.component';
import { PageNotFoundComponent } from './page-not-found.component';

const appRoutes: Routes = [
  // home route
  { path: 'home', component: HomeComponent },
  { path: 'list', component: ListEmployeesComponent },
  { path: 'create', component: CreateEmployeeComponent },
  { path: 'edit/:id', component: CreateEmployeeComponent },
  // redirect to the home route if the client side route path is empty
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  // wild card route
  { path: '**', component: PageNotFoundComponent }
];

In the root component (app.component.html) include a menu item for the home route

<div class="container">
    <nav class="navbar navbar-default">
        <ul class="nav navbar-nav">
            <!-- Include this Home menu item for the home route-->
            <li>
                <a routerLinkActive="active" routerLink="home">Home</a>
            </li>
            <li>
                <a routerLinkActive="active" routerLink="list">List</a>
            </li>
            <li>
                <a routerLinkActive="active" routerLink="create">Create</a>
            </li>
        </ul>
    </nav>
    <router-outlet></router-outlet>
</div>

In our next video we will discuss refactoring our application to include employee feature module.

Video Link


Creating feature module in angular

Suggested Videos
Part 29 - Angular reactive forms put example | Text | Slides
Part 30 - Angular reactive forms post example | Text | Slides
Part 31 - Angular modules explained | Text | Slides

In this video we will discuss creating a feature module in Angular. Let's understand this with an example.


The following is the root module (AppModule) of the application that we have been working with so far in this video series.


// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';
import { HomeComponent } from './home.component';
import { PageNotFoundComponent } from './page-not-found.component';
import { CreateEmployeeComponent } from './employee/create-employee.component';
import { ListEmployeesComponent } from './employee/list-employees.component';

import { EmployeeService } from './employee/employee.service';

@NgModule({
  declarations: [
    AppComponent,
    CreateEmployeeComponent,
    ListEmployeesComponent,
    HomeComponent,
    PageNotFoundComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ReactiveFormsModule,
    HttpClientModule
  ],
  providers: [EmployeeService],
  bootstrap: [AppComponent]
})
export class AppModule { }

At the moment all our application components, directives, pipes and services are in this one module. As we add more features, this module is going to get more complex and extremely difficult to maintain.

What we want to do now is move all the EMPLOYEE feature related components, directives, pipes and services into a separate feature module. Let's name this new feature module - EmployeeModule.

To create this new Employee feature module, let's use Angular CLI. Here is the command.

ng g m employee/employee --flat -m app

The above command 
  • Creates the EmployeeModule in a file with name employee.module.ts
  • Imports EmployeeModule into the root module - AppModule.
Copy and paste the following code in employee.module.ts

// employee.module.ts
import { NgModule } from '@angular/core';
// Exports all the basic Angular directives and pipes
// such as NgIf, NgFor, DecimalPipe etc.
import { CommonModule } from '@angular/common';
// CreateEmployeeComponent uses ReactiveFormsModule directives such as
// formGroup so ReactiveFormsModule needs to be imported into this Module
// An alternative approach would be to create a Shared module and export
// the ReactiveFormsModule from it, so any other module that needs
// ReactiveFormsModule can import it from the SharedModule.
import { ReactiveFormsModule } from '@angular/forms';

// Import and declare the components that belong to this Employee Module
import { CreateEmployeeComponent } from './create-employee.component';
import { ListEmployeesComponent } from './list-employees.component';

@NgModule({
  imports: [
    CommonModule,
    ReactiveFormsModule
  ],
  declarations: [
    CreateEmployeeComponent,
    ListEmployeesComponent
  ],
  // If you want the components that belong to this module, available to
  // other modules, that import this module, then include all those
  // components in the exports array. Similarly you can also export the
  // imported Angular Modules
  // exports: [
  //   CreateEmployeeComponent,
  //   ReactiveFormsModule
  // ]
})
export class EmployeeModule { }

Browser Module v/s Common Module
In the root module(AppModule), we do not have to import CommonModule explicitly because the BrowserModule imports and re-exports CommonModule. So all the directives and pipes provided by the CommonModule are available in the RootModule, because root module imports BrowserModule.

BrowserModule provides services that are essential to launch and run a browser application. BrowserModule should be imported only once and that too only by the root module.

app.module.ts after refactoring

Since we have moved the following components to EmployeeModule, we can remove them from the RootModule.
  • CreateEmployeeComponent
  • ListEmployeesComponent
Similarly ReactiveFormsModule is also not required in the root module. ReactiveFormsModule components, directives and pipes are only needed in EmployeeModule so we moved it there. So at the moment our root module, looks as shown below.

// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { EmployeeModule } from './employee/employee.module';

import { EmployeeService } from './employee/employee.service';

import { AppComponent } from './app.component';
import { HomeComponent } from './home.component';
import { PageNotFoundComponent } from './page-not-found.component';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    PageNotFoundComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    EmployeeModule
  ],
  providers: [EmployeeService],
  bootstrap: [AppComponent]
})
export class AppModule { }

We can still simplify the code in root module. Notice the EmployeeService is still in the root module. We can move this service to the EmployeeModule or CoreModule. We will discuss this in our upcoming videos.

At the moment all our application routes, including the routes to LIST, CREATE & EDIT employees are in one routing module - AppRoutingModule. We will discuss moving EMPLOYEE feature related routes to a separate routing module in our upcoming videos.

Video Link


Creating feature routing module in angular

Suggested Videos
Part 30 - Angular reactive forms post example | Text | Slides
Part 31 - Angular modules explained | Text | Slides
Part 32 - Creating feature module in angular | Text | Slides

In this video we will discuss 
  • Creating a separate routing module for a feature module. 
  • RouterModule forRoot vs forChild

At the moment, all our application routes, including the EMPLOYEE feature module routes like LIST, CREATE, EDIT are present in AppRoutingModule. This module is in app-routing.module.ts file.


For separation of concerns and ease of maintenance, here is what we want to do.
  • Include all the application level routes like HOME, EMPTY PATH & WILD CARD routes in the AppRoutingModule
  • Include all the EMPLOYEE feature module routes like LIST, CREATE & EDIT in a separate EmployeeRoutingModule
Creating Employee feature routing module:
Step 1 : In the "employee" folder create a new file with name employee-routing.module.ts. The following is the common naming convention used when creating a separate routing module for a feature module.

Feature routing module file name convention
featureModule-routing.module.ts

Feature routing module class name convention
FeatureModuleRoutingModule

For example if your feature module name is employee, then the 
  • Routing Module File Name is employee-routing.module.ts
  • Routing Module Class Name is EmployeeRoutingModule
Step 2 : Copy and paste the following code in employee-routing.module.ts file. The code is commented and self-explanatory.

import { NgModule } from '@angular/core';
// Import RouterModule & Routes type
import { RouterModule, Routes } from '@angular/router';

// Import all the components that we will be referencing in the route definitions
import { CreateEmployeeComponent } from './create-employee.component';
import { ListEmployeesComponent } from './list-employees.component';

// Define the routes
const appRoutes: Routes = [
  { path: 'list', component: ListEmployeesComponent },
  { path: 'create', component: CreateEmployeeComponent },
  { path: 'edit/:id', component: CreateEmployeeComponent },
];

// In a feature module forChild() method must be used to register routes
// Export RouterModule, so the it's directives like RouterLink, RouterOutlet
// are available to the EmployeeModule that imports this module
@NgModule({
  imports: [ RouterModule.forChild(appRoutes) ],
  exports: [ RouterModule ]
})
export class EmployeeRoutingModule { }

RouterModule forRoot vs forChild

forRoot() method registers the specified routes. It also creates an instance of the Router service and registers it with the angular's dependency injector.

forChild() method on the other hand only registers the additional specified routes and tells angular to reuse the Router service instance that forRoot has created.

Angular services are singletons. So, to ensure that, there is only one instance of Router service, forRoot() method should be called only once in the main application routing module.

In all the feature routing modules forChild() method should be used to register the additional routes. When the forChild() method is called, Angular Router knows it has to only register the additional specified routes and not to re-register the Angular Router service.

Step 3 : Import EmployeeRoutingModule into EmployeeModule

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';

// Import the EmployeeRoutingModule
import { EmployeeRoutingModule } from './employee-routing.module';

import { CreateEmployeeComponent } from './create-employee.component';
import { ListEmployeesComponent } from './list-employees.component';

@NgModule({
  imports: [
    CommonModule,
    ReactiveFormsModule,
    // Add EmployeeRoutingModule to the imports array
    EmployeeRoutingModule
  ],
  declarations: [
    CreateEmployeeComponent,
    ListEmployeesComponent
  ]
})
export class EmployeeModule { }

Step 4 : Remove the EMPLOYEE feature module routes from AppRoutingModule (app-routing.module.ts)

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { HomeComponent } from './home.component';
import { PageNotFoundComponent } from './page-not-found.component';

const appRoutes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: '**', component: PageNotFoundComponent }
];

@NgModule({
  imports: [ RouterModule.forRoot(appRoutes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule { }

All angular feature modules should be imported before AppRoutingModule

At this point if you launch the application, except the HOME route, all the routes (LIST, CREATE, EDIT) displays the PageNotFoundComponent template. 

When you comment the following WILD CARD route in the AppRoutingModule, the rest of the routes (LIST, CREATE, EDIT) work. If you uncomment the WILD CARD route, the EMPLOYEE feature module routes stop working again.

const appRoutes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  // { path: '**', component: PageNotFoundComponent }
];

Why are the EMPLOYEE feature module routes (LIST, CREATE, EDIT) not working
This is because of the order in which AppRoutingModule and EmployeeModule are imported in the root module AppModule. Notice at the moment, AppRoutingModule is imported before EmployeeModule in the AppModule.

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    PageNotFoundComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    EmployeeModule
  ],
  providers: [EmployeeService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Because AppRoutingModule is imported before EmployeeModule, the routes will be ordered as shown below. Notice, the WILD CARD route is before all the EMPLOYEE feature module routes. Because of this we will never be able to get to the LIST,CREATE and EDIT routes.

{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent },
{ path: 'list', component: ListEmployeesComponent },
{ path: 'create', component: CreateEmployeeComponent },
{ path: 'edit/:id', component: CreateEmployeeComponent },

To fix this all we have to do is, change the import order of the modules in the AppModule. Import EmployeeModule before AppRoutingModule as shown below.

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    PageNotFoundComponent
  ],
  imports: [
    BrowserModule,
    EmployeeModule,
    AppRoutingModule,
    HttpClientModule,
  ],
  providers: [EmployeeService],
  bootstrap: [AppComponent]
})
export class AppModule { }

With the above change the routes will be ordered as shown below and all our EMPLOYEE feature module routes work as expected. For this reason all feature modules should be imported before AppRoutingModule.

{ path: 'list', component: ListEmployeesComponent },
{ path: 'create', component: CreateEmployeeComponent },
{ path: 'edit/:id', component: CreateEmployeeComponent },
{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent },

Video Link


Creating shared module in angular

Suggested Videos
Part 31 - Angular modules explained | Text | Slides
Part 32 - Creating feature module in angular | Text | Slides
Part 33 - Creating feature routing module in angular | Text | Slides

In this video we will discuss creating a shared module in angular.


As the name implies, the shared module contains all the commonly used directives, pipes, and components that we want to share with other modules that import this shared module


Things to consider when creating a shared module
  • The SharedModule may re-export other common angular modules, such as CommonModule, FormsModule, ReactiveFormsModule etc. Instead of writing the same code in every feature module to import these commonly used Angular modules we can re-export them from a SharedModule, so these commonly used Angular Modules are available to all the feature modules that import this SharedModule.
  • The SharedModule should not have providers. This is because, lazy loaded modules create their own branch on the Dependency Injection tree. As a result of this, if a lazy loaded module imports the shared module, we end up with more than one instance of the service provided by the shared module. If this does not make sense at the moment, please do not worry, we will discuss with an example in our upcoming videos. For this same reason, the SharedModule should not import or re-export modules that have providers.
  • The SharedModule is then imported by all the FeatureModules where we need the shared functionality. The SharedModule can be imported by both - eager loaded FeatureModules as well as lazy loaded FeatureModules. We will discuss eager and lazy loading modules in our upcoming videos.
Use the following Angular CLI command to generate a SharedModule

ng g m shared/shared --flat -m employee/employee

Copy and paste the following code in the SharedModule (shared.module.ts)

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    // At the moment we do not have any components in this SharedModule
    // that require directives of CommonModule or ReactiveFormsModule
    // So we did not include them here in the imports array. We can
    // export a module without importing it first
  ],
  declarations: [],
  // Our Employee FeatureModule requires the CommonModule directives
  // such as ngIf, ngFor etc. Similarly, Employee FeatureModule also
  // requires ReactiveFormsModule directives. So export CommonModule
  // and ReactiveFormsModule.
  exports: [
    CommonModule,
    ReactiveFormsModule
  ]
})
export class SharedModule { }

In EmployeeModule (employee.module.ts), remove CommonModule and ReactiveFormsModule references as these modules are now provided by the imported SharedModule

import { NgModule } from '@angular/core';

import { EmployeeRoutingModule } from './employee-routing.module';

import { CreateEmployeeComponent } from './create-employee.component';
import { ListEmployeesComponent } from './list-employees.component';
import { SharedModule } from '../shared/shared.module';

@NgModule({
  imports: [
    EmployeeRoutingModule,
    SharedModule,
  ],
  declarations: [
    CreateEmployeeComponent,
    ListEmployeesComponent
  ]
})

export class EmployeeModule { }

Video Link


Grouping routes and creating component less route in angular

Suggested Videos
Part 32 - Creating feature module in angular | Text | Slides
Part 33 - Creating feature routing module in angular | Text | Slides
Part 34 - Creating shared module in angular | Text | Slides

In this video we will discuss
  • Grouping routes
  • Creating a component less route

Consider the following routes in employee-routing.module.ts file

const appRoutes: Routes = [
  { path: 'list', component: ListEmployeesComponent },
  { path: 'create', component: CreateEmployeeComponent },
  { path: 'edit/:id', component: CreateEmployeeComponent },

];


In our upcoming videos we will discuss lazy loading angular module. One of the requirements to be able to lazy load an angular module is the following.

All the routes in an angular module that you want to lazy load should have the same route prefix.

At the moment, the above 3 routes does not have a common route prefix. To achieve this, modify the above route configuration as shown below.

const appRoutes: Routes = [
  {
    path: 'employees',
    children: [
      { path: '', component: ListEmployeesComponent },
      { path: 'create', component: CreateEmployeeComponent },
      { path: 'edit/:id', component: CreateEmployeeComponent },
    ]
  }
];

Code explanation :
  • Notice we have a parent route with path employees
  • The parent 'employees' route has 3 child routes
  • All the 3 child routes will be pre-fixed with the parent route path - employees
  • Notice the parent route(employees) does not have a component associated with it. That is why this route is called a component less route.
With the above route configuration, we have the following routes
Route Path Description
/employees Displays the list of all employees
/employees/create Allows to create a new employee
/employees/edit/1 Allows to create a edit an existing employee

Notice now, all the routes in this module have the same route prefix. In our upcoming videos we will discuss lazy loading an angular module.

Update the routes in the navigation menu in app.component.html

<li>
    <a routerLinkActive="active" routerLink="employees">List</a>
</li>
<li>
    <a routerLinkActive="active" routerLink="employees/create">Create</a>
</li>

In list-employees.component.ts, modify the code to redirect to the new EDIT route (employees/edit/id)

editButtonClick(employeeId: number) {
  this._router.navigate(['/employees/edit', employeeId]);
}

In create-employee.component.ts, modify the code to redirect to the new 'employees' route

onSubmit(): void {
  this.mapFormValuesToEmployeeModel();
  if (this.employee.id) {
    this.employeeService.updateEmployee(this.employee).subscribe(
      () => this.router.navigate(['employees']),
      (err: any) => console.log(err)
    );
  } else {
    this.employeeService.addEmployee(this.employee).subscribe(
      () => this.router.navigate(['employees']),
      (err: any) => console.log(err)
    );
  }
}

Video Link


Lazy loading in angular

Suggested Videos
Part 33 - Creating feature routing module in angular | Text | Slides
Part 34 - Creating shared module in angular | Text | Slides
Part 35 - Grouping routes and creating component less route in angular | Text | Slides

In this video we will discuss lazy loading angular modules.


At the moment the sample application that we have been working with has 2 modules.
  • Root application module - AppModule
  • Feature module - EmployeeModule

As you add more features to your application you will have more feature modules like ReportsModule, AdminModule etc. As you add more feature modules, the overall application size will continue to grow. At some point you'll reach a tipping point where the application takes a very long time to load. 

Unless, you are using lazy loading, all the modules are eagerly loaded. This means, all the modules in your angular application and their associated components, directives, pipes and services must be downloaded from the server, when the user first visits the application. Depending on the number of modules in your application and the internet speed, this could take a significant amount of time and may very badly affect the end user experience.

To address this problem, we use asynchronous routing, which loads feature modules lazily, on demand. This can significantly reduce the initial load time of your application.

At the moment, the 2 modules (AppModule & EmployeeModule) in our application are eagerly loaded.

We want to lazily load EmployeeModule. To lazy load a module, it has to meet 2 requirements.
  • All the routes in the angular module that you want to lazy load should have the same route prefix
  • The module should not be referenced in any other module. If it is referenced, the module loader will eagerly load it instead of lazily loading it.
Our application already meets the first requirement. All our EmployeeModule routes have the same route prefix i.e employees. We discussed how to do this in our previous video.

At the moment, our application does not meet the second requirement. EmployeeModule that we want to lazy load is referenced in the AppModule. So please delete the EmployeeModule references in the AppModule (app.module.ts)

At this point, if we navigate to any of the EmployeeModule routes (i.e /employees or employees/create or employees/edit/2), we see the PageNotFoundComponent template displayed.

To fix this, we have to lazy load the EmployeeModule. To achieve this, include the following route in app-routing.module.ts file. This new route, lazily loads the EmployeeModule. Make sure the below route is before the wild card route in the AppRoutingModule. Otherwise we would not be able to get to any of the EmployeeModule routes.

{ path: 'employees', loadChildren: './employee/employee.module#EmployeeModule' }

At this point, if we navigate to any of the EmployeeModule routes (i.e /employees or employees/create or employees/edit/2), we see either an empty page or the PageNotFoundComponent template displayed.

But if we include an extra /employees in the path as shown below, then all the EmployeeModule routes work as expected

/employees/employees
/employees/employees/create
/employees/employees/edit/2

To fix this, in employee-routing.module.ts file, change the following routes. We do not need the parent route - 'employees'

const appRoutes: Routes = [
  {
    path: 'employees',
    children: [
      { path: '', component: ListEmployeesComponent },
      { path: 'create', component: CreateEmployeeComponent },
      { path: 'edit/:id', component: CreateEmployeeComponent },
    ]
  }
];

After you remove the 'employees' parent route, the routes should look as shown below.

const appRoutes: Routes = [
  { path: '', component: ListEmployeesComponent },
  { path: 'create', component: CreateEmployeeComponent },
  { path: 'edit/:id', component: CreateEmployeeComponent },
];

With the above changes, the Employee feature module should be lazily loaded. You can confirm this by looking at the Network tab on the Browser Developer Tools.

Video Link


Preloading angular modules

Suggested Videos
Part 34 - Creating shared module in angular | Text | Slides
Part 35 - Grouping routes and creating component less route in angular | Text | Slides
Part 36 - Lazy loading in angular | Text | Slides

In this video we will discuss
  • Different module loading strategies in Angular and the difference between them
  • What is Preloading strategy and how to configure it

Module loading strategies in Angular
  • Eager Loading
  • Lazy Loading
  • Preloading

Eager loading in Angular : With Eager Loading all the modules must be downloaded onto the client machine before the application starts.

angular eager loading
  • If we do not do anything special, by default, the angular modules are eagerly loaded
  • The root application module (AppModule) is always eagerly loaded
  • Eager loading works fine for small applications because a small application usually has, just a few modules. So eagerly downloading those few modules should not take a long time and hence it is not a performance bottle neck in a small application. But Eager loading all modules before the application starts is not right for a medium or large angular applications. In most cases, in a real world angular application we use a combination of these module loading strategies.
  • Only the first request to the application takes a long time, but the subsequent requests from that same client will be faster. This is because, with eager loading, all the modules must be loaded before the application starts. So depending on the number of modules and the internet connection speed, the first request may take a long time, but the subsequent requests from that same client will be faster, because all the modules are already downloaded on to the client machine.
  • There is nothing special that we have to do, for an Angular module to be eager loaded. It just needs to be referenced in the application using imports metadata of @NgModule decorator.
Lazy loading in Angular : Lazy loaded modules are loaded on demand when the user navigates to the routes in those respective modules.

angular lazy loading
  • To lazy load a module, it should not be referenced in any other module. If it is referenced, the module loader will eagerly load it instead of lazily loading it. We discussed lazy loading in detail in our previous video.
  • The main benefit of Lazy loading is, it can significantly reduce the initial application load time. With lazy loading configured, our application does not load every module on startup. Only the root module and any other essential modules that the user expects to see when the application first starts are loaded. In our example here, only the root module and employee module are loaded when the application starts. The rest of the modules i.e ReportsModule and AdminModule are configured to be lazy loaded so they are not loaded when the application starts. Because of this reduced download size, the application initial load time is reduced to a great extent.
  • However there is a downside for lazy loading. When a route in a lazy loaded module is first requested, the user has to wait for that module to be downloaded. We do not have this problem with eager loading, because all the modules are already downloaded, so the end user gets to see the component associated with the route without any wait time.
Now the question that we should be asking ourselves is, why should the application wait to download a lazy loaded module until we navigate to a route in that module. Can the application download the lazy loaded module in the background after the initial bundle that is required to start the application is downloaded.

Well, yes, the lazy loaded modules can be preloaded in the background after the initial start up bundle is downloaded. Here is how it works.

Preloading in Angular : Preloading is the same as lazy loading but happens slightly differently.

angular preloading modules
  • First, the module to bootstrap the application and eager loaded modules are downloaded.
  • At this point, we have the application up and running and the user is interacting with the application.
  • While the application has nothing else to download, it downloads angular modules configured to preload in the background.
  • So, by the time the user navigates to a route in a lazy loaded module, it is already pre-loaded, so the user does not have to wait, and sees the component associated with that route right away.
  • So with preloading modules, we have the best of both the worlds i.e Eager Loading and Lazy Loading.
  • Preloading is also often called Eager Lazy Loading
Configuring Preloading in Angular :

Step 1 : Import PreloadAllModules type from @angular/router package

import { PreloadAllModules } from '@angular/router';

Step 2 : Set preloadingStrategy to PreloadAllModules.

We do this in the configuration object that we pass as a second parameter to the forRoot() method of the RouterModule class.

@NgModule({
  imports: [
    RouterModule.forRoot(appRoutes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [ RouterModule ]
})
export class AppRoutingModule { }

The value for preloadingStrategy property can be one of the following
Value Description
NoPreloading This is the default and does not preload any modules
PreloadAllModules Preloads all modules as quickly as possible in the background
Custom Preload Strategy We can also specify our own custom preloading strategy. We will discuss why and how to implement custom preloading strategy in our next video.

Video Link


Angular custom preloading strategy

Suggested Videos
Part 35 - Grouping routes and creating component less route in angular | Text | Slides
Part 36 - Lazy loading in angular | Text | Slides
Part 37 - Preloading angular modules | Text | Slides

In this video we will discuss implementing custom preloading strategy in Angular.


To control when a lazy loaded module is downloaded onto the client machine, we use preloadingStrategy property. We discussed this in detail in Part 37 of Angular 6 tutorial.


Let us say in our Angular project, we have 2 lazy loaded modules
  • EmployeeModule
  • AdminModule
If we set, preloadingStrategy property to PreloadAllModules, then both the lazy loaded modules will be preloaded in the background.

RouterModule.forRoot(appRoutes, {preloadingStrategy: PreloadAllModules})

On the other hand, if we set preloadingStrategy property to NoPreloading, then none of the lazy loaded modules will be preloaded.

RouterModule.forRoot(appRoutes, {preloadingStrategy: NoPreloading})

So with the following 2 built-in preloadingStrategy options, we can either preload, all lazy loaded modules or none of them.
  • PreloadAllModules
  • NoPreloading
But, what if we want to preload some of the modules and not the other. In our case, let's say we want to preload EmployeeModule, but not the AdminModule. This is when, we create our own Custom Preloading Strategy.

Steps for creating Custom Preloading Strategy in Angular

Step 1 : To create a Custom Preloading Strategy, create a service that implements Angular's built-in PreloadingStrategy abstract class

To generate the service, use the following Angular CLI command
ng g s CustomPreloading

This command generates a file with name custom-preloading.service.ts. Modify the code in that file as shown below.

import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
// Since we are creating a Custom Preloading Strategy, this service
// class must implement PreloadingStrategy abstract class
export class CustomPreloadingService implements PreloadingStrategy {

  constructor() { }

  // PreloadingStrategy abstract class has the following preload()
  // abstract method for which we need to provide implementation
  preload(route: Route, fn: () => Observable<any>): Observable<any> {
    // If data property exists on the route of the lazy loaded module
    // and if that data property also has preload property set to
    // true, then return the fn() which preloads the module
    if (route.data && route.data['preload']) {
      return fn();
    // If data property does not exist or preload property is set to
    // false, then return Observable of null, so the module is not
    // preloaded in the background
    } else {
      return of(null);
    }
  }
}

Step 2 : Import CustomPreloadingService and set it as the Preloading Strategy

In app-routing.module.ts, import CustomPreloadingService

import { CustomPreloadingService } from './custom-preloading.service';

Set CustomPreloadingService as the Preloading Strategy

RouterModule.forRoot(appRoutes, {
  preloadingStrategy: CustomPreloadingService
})

Modify the 'employees' route, and set preload property to true or false. Set it to true if you want the EmployeeModule to be preloaded else false.

const appRoutes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  {
    path: 'employees',
    // set the preload property to true, using the route data property
    // If you do not want the module to be preloaded set it to false
    data: { preload: true },
    loadChildren: './employee/employee.module#EmployeeModule'
  },
  { path: '**', component: PageNotFoundComponent }
];

Video Link



Block-4




What is Angular CLI

Suggested Video Tutorials
Angular 2 tutorial for beginners
ASP.NET Web API Tutorial
Bootstrap tutorial for beginners

In this video we will learn
1. What is Angular CLI
2. Why should we use Angular CLI and the benefits it provide


Before watching this course I strongly recommend to watch our Angular 2 tutorial for beginners course in which we have discussed all the basics of Angular. Once you have a good understanding of the angular basics, it will be easy for you to get the most out of this Angular CLI course.


First let's understand why should we use Angular CLI and what problems it solves.

If you have any experience with Angular, then you already know manually setting up an Angular application from scratch is a laborious and time consuming process. We have to
  1. Create a separate application folder and add the package definition file ( ie. package.json) and other configuration files. We will discuss what these configuration files are in detail in our upcoming videos in this series.
  2. Install the packages using NPM
  3. Create the root application component (i.e AppComponent) as every angular application should have atleast one component which is the root component. This root component bootstraps the angular application. 
  4. Create the root application module (AppModule) as every angular application should have atleast one module which is the root module
  5. Create main.ts file which is the entry point to the application. The code in this file, loads the angular root module - AppModule
  6. Create index.html which hosts our application
You have to manually write all the boilerplate code yourself, which is not only monotonous but also time consuming. If you have an inline view template and inline styles for your component, then it is enough if you just create the TypeScript component class file. But if you have lot of HTML and styles, then for maintainability and separation of concerns, you want your HTML to be in a separate template file and your styles in a separate stylesheet. In this case you will have to manually create the HMTL template and CSS files as well in addition to the component class file.

In a real world application, we will have many components. Just imagine the amount of time we have to spend to create these different component files and the same boilerplate code. In an Angular application, in addition to components, we also have directives, pipes, services etc. Again imagine the amount of time it takes to create that same boilerplate code for all these.

In a real world, we usually have more than one developer working on a given angular project. While all these developers are creating these different files and writing the required boiler plate code, are they following the angular teams best practices and conventions. What if the developers are not following them. How do we enforce them. Well, one way to enforce these is by manual code reviews. Code reviews are not only time consuming but also error prone. 

The other option is to have some tooling in place to address this. Angular CLI is such a tool. It help us create angular applications, components, modules, pipes, directives, services and much more with great speed and consistency while still following the angular teams best practices and conventions.

What is Angular CLI
  1. CLI stands for Command Line Interface. So Angular CLI is command line tool the help us 
  2. Create Angular applications faster and with great consistency
  3. Create the boiler plate code for angular features like components, directives, pipes, services etc.
  4. Create boiler plate code for TypeScript features like classes, interfaces, enums etc.
  5. It follows angular best practices and conventions out of the box
  6. Run Unit and End-to-End (e2e) tests
  7. Create optimised builds for deployment to production
We will see all these in action in our upcoming videos.

No doubt Angular CLI, will greatly help us improve our productivity as it can get an angular app up and running in no time. It can also generate components, directives, pipes, services etc with great speed. However, to get the most out of this tutorial and to understand what CLI does, it is better to understand how to manually create an angular project from scratch. Also learn how to manually create components, pipes, services, modules etc. Once you have a good working knowledge of how these different pieces fit together in an angular application, we can then use tools like Angular CLI to boost our productivity. Otherwise, if a there is a problem with a feature generated by Angular CLI, it might take a very long time to identify what is wrong. We have covered the basics of creating components, services, pipes etc in our Angular 2 course. Here is the link for Angular 2 course.
https://www.youtube.com/watch?v=WWQZCDegWHg&list=PL6n9fhu94yhWqGD8BuKuX-VTKqlNBj-m6

In our next video, we will discuss installing Angular CLI

Video Link


Installing Angular CLI

Suggested Videos
Part 1 - What is Angular CLI | Text | Slides

In this video we will discuss how to install Angular CLI

Prerequisites for installing Angular CLI : To install Angular CLI you should have installed Node 6.9.0 or higher, and NPM 3 or higher


To check the versions that you have on your machine type the following commands in a command window.
  • node -v 
  • npm -v

You can get the latest version of Node and NPM from the following website. Click on the correct download link depending on the Operating System you have.
https://nodejs.org/en/download/

Once you have Node and NPM installed. Run Command Prompt as an administrator and execute the following command. Flag -g installs Angular CLI globally on your machine.
npm install -g @angular/cli

You can also use i as shortcut for install. So the above command can also be rewritten as shown below
npm i -g @angular/cli

If you see a tree structure as shown below, you have Angular CLI installed successfully. 
install angular cli on windows 10

To verify the version of Angular CLI installed, execute the following command
ng -v

At the time of this recording, I have Angular CLI version 1.4.2 installed on my machine as you can see from the screenshot below.
angular cli setup

If you run into any problems installing Angular CLI, follow these steps and hopefully Angular CLI will be installed successfully.

Step 1 : Delete "npm" folder from the following path
C:\Users\Your_UserName\AppData\Roaming

Please note : If you cannot find "AppData" folder, make sure in your windows operating system, you have "Show hidden files, folders, and drives" option is turned on. "AppData" is a hidden folder.

Step 2 : Once you have the "npm" folder deleted, uninstall node.js. On a windows machine you can uninstall node.js from Control Panel\All Control Panel Items\Programs and Features. Right click on "Node.js" and select "uninstall" from the context menu.

Step 3 : Reinstall Node.js by downloading the appropriate installer for your operating system from the following link.
https://nodejs.org/en/download/

Step 4 : Run Command Prompt as an Administrator and try to install Angular CLI again using the following command. Hopefully this time it installs successfully. If not, please leave the problem you are facing as a comment on this video and we will try to help as soon as we can. Also, if you had a problem and you solved it yourself, please let us know what the problem is and how you solved it by leaving a comment, so it could help others with a similar problem. After all, it's all about sharing and learning from each other.
npm install -g @angular/cli

In our next video, we will discuss creating an Angular project from scratch using Angular CLI.

Video Link


Angular CLI Create new project

Suggested Videos
Part 1 - What is Angular CLI | Text | Slides
Part 2 - Installing Angular CLI | Text | Slides

In this video we will discuss 
  1. How to create a new angular project from scratch using Angular CLI
  2. Run the app
  3. Run unit and end-to-end test

In this course we will use Visual Studio Code as the editor. Visual Studio Code is free and you can use it on any platform - Windows, Mac or Linux. If you have not installed it already, please install it by downloading from the following link.
https://code.visualstudio.com/download


To create a new Angular Project, open Command Prompt as an Administrator and execute the following command. This command creates all the required files and also installs all the required packages. Depending on your computer and internet connection speed, this command takes a few minutes to complete.

c:\>ng new MyFirstApp
  • ng is the Angular CLI
  • new for creating a new application
  • MyFirstApp is the name of your angular application
There are several options that we can use with "ng new". We will discuss all these options in our next video.

Once the above command has completed successfully you will see the following messages.
Installed packages for tooling via npm.
Project 'MyFirstApp' successfully created.

So what did this "ng new" command do
  • A new folder with name MyFirstApp is created
  • All the required configuration and source files are created.
  • All the npm dependencies are installed in node_modules folder
  • Unit and end-to-end tests are created
  • The Karma unit test runner is configured
  • The Protractor end-to-end test framework is configured
We will discuss unit tests, end-to-end tests, Karma and Protractor in our upcoming videos.

Please note that all these code and configuration files are created by the Angular CLI out of the box while still following the angular teams best practices and conventions.

Now, go to the folder (MyFirstApp) that contains our angular project, by executing the following command. cd stands for change directory
cd MyFirstApp

Now execute the following command at the command prompt to open the project folder in Visual Studio Code. Notice there is a single space and a DOT after the word code.
code .

At this point in Visual Studio Code you will see all the Angular project files. Also notice node_modules folder, that conatins all the installed packages.
angular cli create new project

We will discuss, what all these files are and their purpose in our upcoming videos.

To run the project using Angular CLI, type the following command at the command prompt. This command builds the application and opens it in our default browser. The flag --open, launches our default browser and runs the application. By default the application runs on port 4200. We can change this port number if required. We will discuss how to do that in our upcoming videos.
ng serve --open

At the moment, the angular development server is running in watch mode, meaning when a file changes, those changes are automatically detected, compiled and the browser reloads to reflect the changes. This is called live reload. We can turn this live reload functionality off, if required. Again we will discuss how to do this in our upcoming videos.

To stop the server, press CTRL + C while you are on the command prompt and then "Y" and ENTER key. This will stop the server.

To run all the unit tests, use the following command
ng test

To run all the end-to-end tests, use the following command
ng e2e

We will discuss Unit tests, end-to-end tests and all the options we can use to run them using Angular CLI in our upcoming videos.

Video Link


Customize Command Prompt

Suggested Videos
Part 1 - What is Angular CLI | Text | Slides
Part 2 - Installing Angular CLI | Text | Slides
Part 3 - Angular CLI Create new project | Text | Slides

In this video we will discuss how to customise command prompt window. You might be wondering why are we talking about customising Command Window in an Angular CLI course. As we know, Angular CLI is a command line tool. We run it using the command prompt window. If we know how to customise the command prompt window to suit our needs, then we have better experience using the Angular CLI. 



If you already know, how to customise the command prompt window, you may skip this video.

As far as Angular CLI is concerned, the most useful command I think is, ng --help. When we type this command in the command prompt window and hit enter key, it displays all the Angular CLI commands and the options we can use with these commands.


As we scroll up in the command prompt window, notice we are not able to see all the commands and their associated options. To fix this we have to increase the buffer size. To increase the buffer size there are 2 simple steps

Step 1 : Right click on the "title bar" of the command window and select "Properties" from the context menu
Customize Command Prompt

Step 2 : Click on the "Layout" tab and set the "Height" property to 9999 under "Screen Buffer Size" section, and click "OK"
increase number of lines in command prompt

With this change in place, execute that same command ng --help. Notice now we can see all the commands and their associated options.

There is lot of help text displayed on the screen. If you want to find a specific command you can use the search feature of the command window. To use the search feature, right click on the "title bar" of the command window and select "Edit" from the context menu. You can then use the "Find" window to search for the command you are looking for.

To redirect the output of ng --help command to the windows clipboard, use the CLIP command as shown below.
ng --help | clip

Once you have the output copied in the clipboard you can paste it anywhere you want it. For example in a notepad, word document etc.

You can also redirect the output directly to a text document using the following command. This command creates a text document with name MyTextDoc.txt  in the folder where you have executed the command. This text documents will have the output of the command ng --help.
ng --help >MyTextDoc.txt

Similarly you can also redirect the output to a word document.
ng --help >MyWordDoc.doc

From the properties window of the command prompt you can also change the cursor size, font size, font colour and background colour.

In our next video we will discuss all the options we can use with the Angular CLI's "ng new" command

Video Link


Angular CLI ng new options

Suggested Videos
Part 2 - Installing Angular CLI | Text | Slides
Part 3 - Angular CLI Create new project | Text | Slides
Part 4 - Customize Command Prompt | Text | Slides



In this video we will discuss some of the common options that we can use with ng new command.



The table below shows the common options, their data types, default values, alias and a short description of what they do.
Flag Type Default Alias Purpose
--dry-run Boolean false -d Run through without making any changes. Just reports the files that will be created
--skip-install Boolean false -si Skip installing packages
--skip-tests Boolean false -st Skip creating tests
--inline-style Boolean false -is Use inline styles when generating the new application
--inline-template Boolean false -it Use inline templates when generating the new project

Video Link


Angular CLI configuration file

Suggested Videos
Part 3 - Angular CLI Create new project | Text | Slides
Part 4 - Customize Command Prompt | Text | Slides
Part 5 - Angular CLI ng new options | Text | Slides

In this video we will discuss the significance of the Angular CLI configuration file (.angular-cli.json)


This is the configuration file that the Angular CLI uses. As you can see from the image, it has several settings in it.
Angular CLI configuration file


The settings from this file are used when we
  • Generate angular features likes components, pipes, services etc
  • Run unit and end-to-end tests
  • Build the application etc.
We will be revisiting this file many times as we progress through this Angular CLI course.

The table below shows some of the settings and their purpose. We will discuss the other settings and their purpose as we progress through the course.
Setting Purpose
project : name Name of the project
apps: root The root directory of the application. Default is src. We can change this using the "source-dir" option when generating a new angular project using the "ng new" command
apps: outDir The output directory for build results. Default is dist
apps: assets List of application assets that you want to copy when building your project. By default, the src/assets/ folder and src/favicon.ico are copied over
apps: index The name of the start HTML file which is index.html by default
apps: main The name of the main entry-point file. main.ts by default
apps: polyfills The name of the polyfills file. Angular is built on the latest standards of the web platform. Targeting such a wide range of browsers is challenging because not all browsers support all features of modern browsers. This can be compensated by using polyfill scripts that implement missing features in JavaScript
apps: styles Global styles to be included in the build. Default is styles.css. We can also use less or scss. To change to less or scss, use the "style" option when generating a new angular project using the "ng new" command
apps: prefix The selector prefix to apply for the generated components. Default is "app". This can be changed by using the "prefix" option when generating a new angular project using the "ng new" command

The important point to take away is that the values in the Angular CLI configuration file depends on the options that you have used with the "ng new" command when generating a new angular project. For example, if you do not use the --prefix option with the "ng new" command, then the default value "app" is stored in the configuration file for "prefix" setting. So the root component (AppComponent) that is created at the application generation time has "app" as the selector prefix.

Instead if you want "pragim" as the prefix, use --prefix flag along with "ng new" command. When you do this several things happen
  1. "pragim" is stored as the "prefix" setting value in .angular-cli.json configuration file
  2. "pragim" is used as the selector prefix for the root component that the "ng new" command generates
  3. Any new component that you generate in the future using the following command will also have "pragim" as the selector prefix
    ng generate component componentName
  4. If you want to override the prefix setting in the angular cli configuration file, you can use --prefix option with the generate command as shown below. This will generate the component "xyz" with the prefix "tech" instead of "pragim"ng generate component xyz --prefix tech
  5. Some of the options like --prefix can be used with several commands like ng new and ng generate
Please note : If you generate a project with --skip-install flag and when you try to generate a new component using "ng new" command before executing the "npm install" command you will get the following error
node_modules appears empty you may need to run npm install

To fix this, please first execute "npm install" to install the required npm packages and then generate the component.

Video Link


Angular CLI project structure - 1

Suggested Videos
Part 4 - Customize Command Prompt | Text | Slides
Part 5 - Angular CLI ng new options | Text | Slides
Part 6 - Angular CLI configuration file | Text | Slides

In this video we will discuss the Angular project structure. I have split this into 2 videos. In this video, we will discuss all the files and folders in the Angular project, except the "src" folder and it's contents. In our next video we will discuss the "src" folder and it's contents.


One of the easiest ways to create a working angular project, is by using the Angular CLI. The following Angular CLI command creates a working Angular Project out of the box
ng new AngularProject


The image below shows the Angular project in Visual Studio Code.
angular cli project structure

As you can see there are several files in the project. The table below shows the purpose of each file/folder.
File / Folder Purpose
package.json This file contains the packages to build and run our application. It contains two sets of packages, dependencies and devDependencies. The dependencies are essential for running the application. The devDependencies are only required to develop the application. These packages are installed into the node_modules folder by the Node Package Manager (npm), when npm install commaned is excuted. You can also add your own custom scripts here.

"scripts" property in package.json file contains the useful npm commands. Notice we have "start": "ng serve". This means when we execute npm start it executes ng serve which builds and starts the server. In addition if you also want to launch the browser and open the application
CHANGE "start": "ng serve" TO "start": "ng serve --open"
node_modules The packages specified in package.json file are installed into this folder when we run npm install command
e2e Folder Contains end-to-end tests and their configuration files. We will discuss end-to-end tests in our upcoming videos
.angular-cli.json This is the Angular CLI configuration file. We discussed the use of this file in our previous video.
.editorconfig Configuration file for Visual Studio Code. The settings in this file let you set certain code style guidelines. For example what indent_style do you want - spaces or tabs and what should be the indent size etc. You can share this editorconfig file with other developers to maintain consistent coding styles. To read more about editor configuration please visit http://editorconfig.org
.gitignore This file is used to determine files and folders you don't want to check in to source control. For example one of the folders we do not want to check in to source control is /dist folder which is auto generated when we build the application. So this folder is listed in this file. So, all the files and folders listed in this file are ignored, when a change set is checked in to source control.
karma.conf.js Karma is the unit test runner for angular applications. As the name implies, karma.conf.js is the configuration file for Karma.
protractor.conf.js Protractor is an end-to-end test framework for Angular applications. As the name implies, protractor.conf.js is the configuration file for Protractor.
README.md This is a README file which contains the commonly used Angular CLI commands out of the box. You may enhance it with your own project documentation so that anyone checking out the repo knows the commands to use to build, run and test your app.
tsconfig.json This is the TypeScript compiler configuration file. This file has several TypeScript compiler configuration settings. For example, to compile TypeScript to JavaScript on saving a TypeScript file set compileOnSave setting to true. If you do not want .map files to be generated, set sourceMap to false. .map files are used for debugging your application.
tslint.json Angular has a linting tool that checks our TypeScript code for programmatic and stylistic errors as well as non-adherence to coding standards and conventions. tslint.json is the configuration file for linting. We will discuss the settings in this file when we discuss linting in our upcoming videos.

In our next video we will discuss the "src" folder and it's contents.

Video Link


Angular CLI project structure - 2

Suggested Videos
Part 5 - Angular CLI ng new options | Text | Slides
Part 6 - Angular CLI configuration file | Text | Slides
Part 7 - Angular CLI project structure - 1 | Text | Slides


This is continuation to Part 7. In Part 7 we discussed all the files and folders in angular project except the "src" folder and it's contents. In this video we will discuss the "src" folder and it's contents.


File / Folder Purpose
src folder As the name implies, this folder contains all our angular project source code. Components, templates, pipes, services, images, styles etc that our angular application needs are present in this folder. The rest of the files and folders that are present outside this folder, are there to support building our angular application
assets As the name implies, the assets folder contains the assets of your application like images and anything else to be copied when you build your application
environments This folder contains the environment files. By default we have 2 environment files. environment.ts is for for development environment. Notice production property in this file is set to false. environment.prod.ts is for production. Notice in this file production property is set to true as expected. The build system defaults to the dev environment which uses `environment.ts`, but if we do a production build environment.prod.ts will be used. The file and environment mapping is in Angular CLI configuration file (.angular-cli.json)
favicon.ico This is the favorite icon for your application which is typically displayed in the browser address bar and next to the page name in a list of bookmarks. Angular CLI provides this favorite icon out of the box. You may replace this favicon with your own company favicon
index.html The main HTML page that is served when someone visits your site
main.ts The main entry point for the application. This file contains the code to bootstrap the application root module (AppModule)
polyfills.ts This is the polyfills file. Angular is built on the latest standards of the web platform. Targeting such a wide range of browsers is challenging because not all browsers support all features of modern browsers. This can be compensated by using polyfill scripts as they implement the missing features in JavaScript. So these polyfills allow us to use an API regardless of whether it is supported by a browser or not
styles.css This file contains the global styles of our application. Styles that are local and specific to a component are often defined with in the component itself for easier maintenance
test.ts This file is the main entry point for unit tests and loads all the .spec and framework files
tsconfig.app.json TypeScript compiler configuration for the Angular app
tsconfig.spec.json TypeScript compiler configuration for the unit tests
typings.d.ts This is the TypeScript typings file. Many JavaScript libraries, such as jQuery, Angular etc extend the JavaScript environment with features and syntax that the TypeScript compiler doesn't recognize natively. When the typeScript compiler doesn't recognize something, it throws an error. So, we use TypeScript type definition files to tell the compiler about those libraries. These TypeScript type definition files have the extension d.ts. TypeScript editors leverage these type definition files to display type information

Many libraries include type definition files in their npm packages. Angular is one such library. For example, if you look inside node_modules/@angular/core/ folder in an Angular application, it already contains the type definition files. All the files that have the extenstion d.ts are the type definition files. We will discuss more about these type definition files in our upcoming videos
app.component.
{ts,html,css,spec.ts}
The root component (AppComponent) TypeScript, HTML template, StyleSheet and Spec files
app.module.ts This is the root application module (AppModule)

Video Link


Angular cli generate component

Suggested Videos
Part 6 - Angular CLI configuration file | Text | Slides
Part 7 - Angular CLI project structure - 1 | Text | Slides
Part 8 - Angular CLI project structure - 2 | Text | Slides

In this video we will discuss generating components using Angular CLI.

You must have the npm packages installed to be able to generate components using Angular CLI. Otherwise when we try to generate components using the ng generate command we will get the following error.
node_modules appears empty, you may need to run 'npm install'


The following command creates a new Angular project with name "myProject" but it does not install the npm packages as we have used -si flag. The -si flag as we know skips installing the npm packages.
ng new myProject -si


At this point if we try to generate a new component using the following ng generate command, it reports an error - node_modules appears empty, you may need to run 'npm install'
ng generate component abc

We will have to first execute npm install command to install the required packages. Once this is done we will be able to generate components.

To generate a component use the following Angular CLI command
ng generate component ComponentName

OR the shortcut as shown below. In the following command the letter g stands for generate and the letter c stands for component
ng g c ComponentName

When we execute this command (ng g c abc) , several things happen
  • A folder with name abc is created
  • The component files (Component class, View template, CSS file and the spec file ) are created and placed inside the folder "abc"
  • The root module file (app.module.ts) is also updated with our new component i.e the required import statement to import the abc component from the component file is included and the component is also declared in the declarations array of the @NgModule() decorator
angular cli generate component example

Placing the generated component folder in a different folder : By default a separate folder is created for every new component that we generate, and the component files (.ts, .css, .html & .spec) are placed in this folder. This newly created folder is placed in the app folder by default. If you want the newly created folder to be placed in a different folder other than the app folder, simply include the folder name in the ng generate command as shown below.
angular cli generate component in folder

Notice now, the newly created "xyz" component folder is placed inside "abc" folder instead of the "app" folder
angular cli generate new component

Generating a new component without a folder : To create a component without a folder, use --flat option with the ng generate command
angular cli generate component without folder

Notice for the newly generated "pqr" component a separate folder is not created. The component files are placed in the "app" folder.
angular cli generate component command

Placing the flat component files in a different folder other than app : A flat component is a component that is created with --flat option. This component does not have it's own folder. By default the flat component files are placed in the "app" folder. If you want to place them in a different folder instead, specify the folder name along with the ng generate command.
angular cli flat component

Notice, the newly generated "jkl" component files are placed in "abc" folder instead of the "app" folder.
angular generate flat component.png

Using --dry-run flag with component generation : Just like how we can use the --dry-run flag with "ng new" command, we can also use it with ng generate command. The --dry-run flag reports the files and folders that will be generated, without actually generating them. Once you are happy with what it is going to generate, you can remove the --dry-run flag and execute the command.

For example, the following ng generate command reports that it creates an external template and stylesheet for the component. It also generates a spec file (unit test file). Notice we have run the command with -d flag, so it only reports the files it is going to generate, without actually generating them.
angular cli generate component dry run

If you want an inline template and styles instead of an external template and stylesheet, use -it flag for inline template and -is flag for inline styles. Along the same lines, if you do not want a spec file use --spec=false. Notice we are also using the -d flag.
angular generate flat component

To use sass instead of CSS with your component, use the --style=scss flag with ng generate command. If you want less use --style=less
angular cli generate component with scss

Video Link


Angular cli generate service

Suggested Videos
Part 7 - Angular CLI project structure - 1 | Text | Slides
Part 8 - Angular CLI project structure - 2 | Text | Slides
Part 9 - Angular cli generate component | Text | Slides

In this video we will discuss generating services using the Angular CLI. Generating services is similar to generating components.


To generate a component we use
ng generate component componentName OR ng g c componentName 


Similarly to generate a service we use
ng generate service serviceName OR ng g s serviceName

For example, to generate a customer service we use the following command. 
ng generate service customer

The above command generates the service and the spec file. What it does not do is register the service. Remember for us to be able to use the service, we must register the service. 

We can do it manually after creating the service or we can tell Angular CLI to register our service with a module, using --module option. We can also use it's alias -m

The following command not only generates employee service, it also registers our service witht the AppModule
ng generate service employee -module=app.module

The above command can also be rewritten using aliases
ng g s employee -m=app.module

We can also use the --dry-run flag or it's alias -d to see what Angular CLI generates. Notice in the following command we are using -d option, so Angular CLI simply report the files it is going to generate

ng g s student -d

The above command generates the service and the spec file. If you do not want the spec file, simply set --spec=false

ng g s student -d --spec=false

When generating a component, Angular CLI by default creates a folder for the component and places all the component files in that folder. A service on the other hand will not have it's own folder. If you want a folder of it's own for a service that the Angular CLI is generating, set --flat option to false as shown below.

ng g s student -d --spec=false --flat=false

Video Link


Angular cli generate module

Suggested Videos
Part 8 - Angular CLI project structure - 2 | Text | Slides
Part 9 - Angular cli generate component | Text | Slides
Part 10 - Angular cli generate service | Text | Slides

In this video we will discuss generating modules using the Angular CLI. 

To generate a module use
ng generate module moduleName OR ng g m moduleName


For example to generate a students module we could use 
ng generate module students -d OR ng g m students -d


Please note : Since we are using the --dry-run flag, the module file and folder is not actually created. We only get the report of the files and folders that will be created.

The above command generates the students module inside students folder. Remember for us to be able to use this newly generated module, we must import it in the root module.

We can do it manually after creating the module or we can tell Angular CLI to import our newly generated module into the root module using --module option. We can also use it's alias -m

The following command not only generates students module, it also imports it into the root module (AppModule)
ng g m students -d -m=app.module

By default a spec file is not generated. If you also want a spec file to be generated use the --spec option
ng g m students -d -m=app.module --spec=true

When generating a module, Angular CLI by default creates a folder for the module and places the module files in that folder. If you do not want a dedicated folder for the module you are generating, use --flat option.
ng g m students -d -m=app.module --spec=true --flat=true

Unitil now, we have been using the --dry-run option. Now let's remove the -d option and execute the command so the module is actually created.
ng g m students -m=app.module --spec=true --flat=true

The above command not only creates the students module, it also imports it into the root module (AppModule). If we look inside app.module.ts file, notice
  1. The required import statement to import students module is included
  2. The students module is also included in the "imports" array
Video Link


angular cli generate directives, pipes and routing guards

Suggested Videos
Part 9 - Angular cli generate component | Text | Slides
Part 10 - Angular cli generate service | Text | Slides
Part 11 - Angular cli generate module | Text | Slides

In this video we will discuss generating directives, pipes and routing guards using the Angular CLI.


Generating directives, pipes, routing guards and other angular features is very similar to generating component and services. We discussed generating components and services using the Angular CLI in our previous videos in this course.


Angular Feature Complete Command Alias
Directive ng generate directive directiveName ng g d directiveName
Pipe ng generate pipe pipeName ng g p pipeName
Routing Guard ng generate guard guardName ng g g guardName

Please note : When you try to generate a directive, pipe or a component, and if you have multiple modules in your angular project you may get the following error
More than one module matches. Use skip-import option to skip importing the component into the closest module.

The reason we are getting this error is we have more than one module in our angular project, so Angular CLI does not know with which module the newly generated directive, pipe or component should be registered. So we have 2 options here.
  1. Use --skip-import option to tell Angular CLI not to import and register the generated component, directive or pipe   
    ng g d directiveName --skip-import -d
  2. Use --module option or it's alias -m to tell Angular CLI the module with which we want our newly generated component, directive or pipe should be registered.   
    ng g d directiveName -m=app.module -d
If you have just one module in your Angular project, then you wouldn't get this error, as the angular cli will automatically import and register the newly generated component, directive or pipe with that one existing module.

When genearting certain angular features like services or routing guards, you will not get this error, even when you have multiple modules in your project, because by default, Angular CLI does not try to import and register these features.

Please note that we can always use the following options along with ng generate command to customise the generation of directives, pipes and routing guards using the Angular CLI.

Option Purpose
flat Specifies if a dedicated folder should be created
module Specifies the module with which the newly generated angular feature should be rigstered
spec Specifies if a spec file should be generated

Video Link


Angular cli generate class, interface and enum

Suggested Videos
Part 10 - Angular cli generate service | Text | Slides
Part 11 - Angular cli generate module | Text | Slides
Part 12 - Angular cli generate directives, pipes and routing guards | Text | Slides

So far we have discussed generating angular features like components, services, directives etc. We can use the Angular CLI to generate TypeScript features as well. In this video we will discuss generating TypeScript features like classes, interfaces and enumerations using the Angular CLI.


As you have seen throughout this course, Angular CLI provides consistent set of commands for generating features. 


To generate a class use
ng generate class className or ng g cl className

For example, to generate an employee class use
ng g cl employee

The above command places the employee class directly in the "app" folder. Instead if you want the employee class in a different folder, simply prefix the name of the folder. The command below creates a folder with name "employee" and then creates the "employee" class in it.
ng g cl employee/employee

By default, a spec file is not created for the class. If you want a spec file to be generated set --spec option to true.
ng g cl employee/employee --spec=true

To generate an interface use
ng generate interface interfaceName or ng g i interfaceName

To generate an enum use
ng generate enum enumName or ng g e enumName

Video Link


Linting TypeScript

Suggested Videos
Part 11 - Angular cli generate module | Text | Slides
Part 12 - Angular cli generate directives, pipes and routing guards | Text | Slides
Part 13 - Angular cli generate class, interface and enum | Text | Slides

In this video we will discuss Linting TypeScript Code

Angular has a linting tool that checks our TypeScript code for programmatic and stylistic errors as well as non-adherence to coding standards and conventions. tslint.json is the configuration file for linting. This file contains all the default rules for linting our code.


For the purpose of this demo I have created a brand new Angular project using the following command.
ng new AngularProject

Use the following command to lint the code
ng lint


Since we have just generated a new angular project and all the code in the project is auto-generated, we do not have any linting errors and we get the message - All files pass linting.

We also see the following warning
Warning: The 'no-use-before-declare' rule requires type checking

Basically this warning is saying, if 'no-use-before-declare' rule is enabled we need to use --type-check option with the ng lint command
ng lint --type-check

'no-use-before-declare' rule is enabled out of the box and it disallows usage of variables before their declaration. To understand what this means, place the following sayHello() function in AppComponent class in app.component.ts file.

sayHello() {
  var message = 'Hello';
  message = message + ' Pragim';
  console.log(message);
}

At this point, execute ng lint command again with --type-check option. 

ERROR: C:/AngularProject/src/app/app.component.ts[12, 17]: variable 'message' used before declaration
ERROR: C:/AngularProject/src/app/app.component.ts[13, 5]: Forbidden 'var' keyword, use 'let' or 'const' instead

Lint errors found in the listed files.

Out of the box, "no-var-keyword" rule is also enabled by default. Turn this rule off by setting it's value to false in tslint.json
"no-var-keyword": true

Run ng lint command again with --type-check option

Notice, now we only get 1 linting error
variable 'message' used before declaration

Now modify the code in sayHello() function as shown below.

sayHello() {
  var message = 'Hello';
  message = message + ' Pragim';
  console.log(message);
}

Run ng lint command again with --type-check option. Notice now we do not get any linting errors.

Variables declared with let keyword are not accessible before they are declared. So this rule 'no-use-before-declare' can be safely disabled, if you have 'no-var-keyword' rule enabled. 

When 'no-use-before-declare' rule is disabled and when we run ng lint command without --type-check option, we will no longer get the below warning 
The 'no-use-before-declare' rule requires type checking

Video Link


Angular tslint rules

Suggested Videos
Part 12 - Angular cli generate directives, pipes and routing guards | Text | Slides
Part 13 - Angular cli generate class, interface and enum | Text | Slides
Part 14 - Linting TypeScript | Text | Slides

In this video we will discuss some of the common angular linting rules in tslint.json file. You may modify these rules depending on your project requirements.


Here are some of the common linting rules
  • quotemark rule specifies whether you want single or double quotes
  • no-trailing-whitespace rule disallows trailing whitespace at the end of a line
  • semicolon rule specifies that a line should be terminated with a semicolon
  • comment-format rule specifies that all single-line comments must begin with a space
  • component-class-suffix rule enforces that a component class should end with the suffix Component
  • use-life-cycle-interface rule enforces that you add the implements keyword for every lifecycle hook you use


Some of the linting errors support automatic fix. To have these linting errors fixed automatically, run ng lint command with the --fix option.
ng lint --fix

To see the options that can be used with ng lint command, use
ng lint --help

At the moment, Visual Studio Code is not able to show any linting rule violations. In our next video, we will discuss how to display linting errors in Visual Studio Code so we can fix them as we are writing code.

Video Link


TSLint in Visual Studio Code

Suggested Videos
Part 13 - Angular cli generate class, interface and enum | Text | Slides
Part 14 - Linting TypeScript | Text | Slides
Part 15 - Angular tslint rules | Text | Slides

In this video we will discuss, How to display linting errors in Visual Studio Code


At the moment, our editor Visual Studio Code does not show linting errors. It would be nice if Visual Studio Code can display these linting errors so we can fix them as we are writing code. To achieve this install Visual Studio Code extension - TSLint.


To install this extension
  1. Click on the "View" menu in "Visual Studi Code" and select "Extensions" from the context menu
  2. In the "Search Extensions in Marketplace" textbox type TSLint install tslint in visual studio code
  3. Click the "install" button
  4. Once installed, restart Visual Stduio Code to activate TSLint
At this point, in Visual Studio Code we will be able to see linting errors and we have the opportunity to fix them as we are developing our application.
visual studio code lint plugin

Once you click on the line where you see a linting error, a light bulb appears on the left margin and when you click on the light bulb you will see 1 to 3 options
visual studio code typescript lint

You can click on the respective options
  1. To have the linting errors fixed automatically depending on whether the issue supports automatic fix or not
  2. To disable that specific rule
  3. To get documentation of the rule
To disable linting in VS code
  1. Click on the "View" menu in "Visual Studi Code" and select "Extensions" from the context menu
  2. In the "EXTENSIONS" window, expand "INSTALLED" section
  3. Click the "SETTINGS" icon against TSLint extension
  4. Select "Disable (Always)" option disable vs code linting
  5. Restart Visual Studio Code
Video Link


Angular Routing

Suggested Videos
Part 14 - Linting TypeScript | Text | Slides
Part 15 - Angular tslint rules | Text | Slides
Part 16 - TSLint in Visual Studio Code | Text | Slides

Implementing routing in an Angular application involves many small steps. Angular CLI does a pretty good job in having some of these routing steps implemented out of the box by just using --routing option.


Before we discuss, how we can use Angular CLI to implement routing let's setup routing manually so we understand all the moving parts as far as implementing routing is concerned.


Using the following command, first create a brand new Angular project using the Angular CLI. 
ng new employeeManagement

We named it employeeManagement. Let's assume we are using this application to manage employees. Out of the box, Angular CLI has created the root component - AppComponent. In addition let's create the components in the table below. The table shows the component name, it's purpose and the routes we are going to use to get to these components.
Component Purpose Route
home This is the home component /home
employees This component displays the list of employees /employees
pageNotFound This component is used when a user tries to navigate to a route that does not exist /nonExistingRoute

Let's generate the above components using Angular CLI. Use the following commands to generate the components. Angular CLI not only generates these components, it also imports and registers the components in the root module.
Component Command
home ng g c home
employees ng g c employees
pageNotFound ng g c pageNotFound

At this point execute the following Angular CLI command
ng serve --open

This builds and launches the application and you will see the following page.
angular routing explained

Here are the steps to implement routing in Angular
Step 1 : Set <base href> in the application host page which is index.html. The <base href> tells the angular router how to compose navigation URLs. This is already done for us by the Angular CLI, when we created this project.

<base href="/">

Step 2 : Import the RouterModule into the application root module AppModule. The Router Module contains the Router service and Router directives such as (RouterLink, RouterLinkActive, RouterOutlet etc). So for us to be able to implement routing, we first need to import the Router Module in our AppModule. So in app.module.ts make the following 2 changes

// Import RouterModule
import { RouterModule } from '@angular/router';

// Include RouterModule in the "imports" array of the @NgModule() decorator
@NgModule({
  declarations: [...
  ],
  imports: [
    BrowserModule,
    RouterModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 3 : Configure the application routes. 

To configure routes, we first need to import Routes type from '@angular/router'. If you look at the definition of Routes type, it is actually an array of Route objects. This Routes type is not required for the application to work. However, using it provides us intellisense and compile time checking. For example, mis-spelled properties of the Route object will be reported as errors.

import { RouterModule, Routes } from '@angular/router';

// Each route maps a URL path to a component
// The 3rd route specifies the route to redirect to if the path
// is empty. In our case we are redirecting to /home
// The 4th route (**) is the wildcard route. This route is used
// if the requested URL doesn't match any other routes already defined
const appRoutes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'employees', component: EmployeesComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: '**', component: PageNotFoundComponent }
];

// To let the router know about the routes configured above,
// pass "appRoutes" constant to forRoot(appRoutes) method
// We also have forChild() method. We will discuss the difference
// and when to use one over the other in our upcoming videos
@NgModule({
declarations: [...
],
imports: [
  BrowserModule,
  RouterModule.forRoot(appRoutes)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Step 4 : Specify where you want the routed component view template to be displayed using the <router-outlet> directive. In our case we want them to be displayed in the root component AppComponent. So in the root component view template i.e in app.component.html, replace all the existing HTML with <router-outlet></router-outlet>

At this point we should have routing working in our application. Build and run the application using the Angular CLI command : ng serve --open
  • Notice the URL in the browser. We have /home in the URL and we see 'home works'! displayed.
  • Now in the URL remove '/home', and type '/employees' and press the enter key. Notice the message 'employees works!' is displayed.
  • Now in the URL remove '/employees', and type '/abc' and press the enter key. '/abc' is not a valid route so the message 'page-not-found works!' is displayed.
  • Now remove '/abc' from the URL and press the enter key. Notice we are redirected to '/home' (the default route) and 'home works'! is displayed.
Step 5 : Tie the routes to application menu. Routing is working as expected, but we have to manually type the URL in the address bar. Instead let's include links to our home and employees routes. Let's do this in the Root component(AppComponent). Include the following HTML in app.component.html.

The routerLink directive tells the router where to navigate when the user clicks the link.
The routerLinkActive directive is used to add the active bootstrap class to the HTML navigation element whose route matches the active route.

<div style="padding:5px">
    <ul class="nav nav-tabs">
        <li routerLinkActive="active">
            <a routerLink="home">Home</a>
        </li>
        <li routerLinkActive="active">
            <a routerLink="employees">Employees</a>
        </li>
    </ul>
    <br/>
    <router-outlet></router-outlet>
</div>

We are using Bootstrap nav component to create the menu. We discussed Bootstrap nav component in Part 27 of Bootstrap tutorial. To install bootstrap execute the following npm command
npm install bootstrap@3 --save

Once Bootstrap is installed, open .angular-cli.json file and specify the path to the Bootstrap stylesheet in the styles property as shown below.
"styles": [
  "../node_modules/bootstrap/dist/css/bootstrap.min.css",
  "styles.css"]

At this point build and run the application using the following Angular CLI command. Routing should be working as expected.

ng serve --open

The following are the directives provided by the RouterModule

routerLink
Tells the router where to navigate when the user clicks the navigation link

routerLinkActive 
  • When a route is active the routerLinkActive directive adds the active CSS class. When a route becomes inactive, the routerLinkActive directive removes the active CSS class. 
  • The routerLinkActive directive can be applied on the link element itself or it's parent. In this example, for the active route styling to work correctly, routerLinkActive directive must be applied on the <li> element and not the <a> element.
router-outlet
Specifies the location at which the routed component view template should be displayed 

At the moment routing is implemented in the root module - AppModule. However, for separation of concerns and maintainability, it is better to implement routing in a separate Routing module and then import that routing module in the AppModule. In a later video, we will discuss how to move routing into it's own routing module. 

As we have seen throughout this video, there are many moving parts that we have to remember, to implement routing correctly in an angular application. In our next video, we will discuss, the routing workflow and how routing actually works in Angular, by connecting all these little moving parts.

Video Link


How routing works in angular

Suggested Videos
Part 15 - Angular tslint rules | Text | Slides
Part 16 - TSLint in Visual Studio Code | Text | Slides
Part 17 - Angular Routing | Text | Slides

In this video we will discuss, How routing works in an angular application. This is continuation to Part 17. Please watch Part 17 from Angular CLI tutorial before proceeding.


As you have seen in our previous video, there are many small steps that you have to remember, to implement routing correctly in an angular application. Let's quickly recap those steps.


Step 1 : Set <base href> in index.html.

Step 2 : Import the RouterModule into the application root module AppModule.

Step 3 : Configure the application routes. 

Step 4 : Specify where you want the routed component view template to be displayed using the <router-outlet> directive

Step 5 : Create a navigation menu and tie the configured routes with the menu using the routerLink directive. Optionally, use the routerLinkActive directive to style the current route that is active, so the user knows the page that he is on, in the application.

Now, let's connect all these small steps and see how routing actually works.

1. We have built the "Home" and "Employees" links using the RouterLink directive. The RouterLink directive  tells the angular router where to navigate when the respective links are clicked. So for example, when we click on the "Home" link, the angular Router includes '/home' in the URL.

2. When the URL changes the angular router looks for the corresponding route in the route configuration. In this case the URL changed to /home, so the router looks for the home route. We have the 'home' route already configured. In the route configuration, we have specified to use the HomeComponent.

3. So the angular router knows to display the HomeComponent view template, but the question is where should the HomeComponent view template be displayed.

4. At this point, the Angular router looks for the <router-outlet> directive. The home component view template is then displayed at the location where we have the <router-outlet> directive. In our case, we placed the <router-outlet> directive in the root component (AppComponent) because that is the top level component where we want our routed component templates to be displayed.

5. We specified 'app-root' as the selector for the root component (AppComponent). This selector (app-root) is used as a directive in the application host page i.e index.html. So along with the navigation menu HTML that we already have in the root component, the HomeComponent view template is also display in index.html page.

6 . Now when we click on the "Employees" link, Steps 1 to 5 happen in the order specified and the HomeComponent view template is replaced with the EmployeesComponent view template.

Hope you are now able to connect all the dots and have a good understanding of all the small steps of implementing routing in an angular application.

Please note : When configuring routes in our previous video, we imported Routes type from '@angular/router'. If you look at the definition of Routes type, it is actually an array of Route objects. This Routes type is not required for the application to work. Even if we remove the Routes type declaration from appRoutes as shown below, the application routing works exactly the same way as before. However, using it provides us compile time checking if we mis-spell the properties of the Route object.

Notice the type declaration : Routes is removed from appRoutes constant
const appRoutes = [
  { path: 'home', component: HomeComponent },
  { path: 'employees', component: EmployeesComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: '**', component: PageNotFoundComponent }
];

At the moment routing is implemented in the root AppModule. However, for separation of concerns and maintainability, it is better to implement routing in a separate Routing module and then import that routing module in the AppModule. In our next video, we will discuss how to move routing into a separate routing module. 

Video Link


Implementing routing in separate module in angular

Suggested Videos
Part 16 - TSLint in Visual Studio Code | Text | Slides
Part 17 - Angular Routing | Text | Slides
Part 18 - How routing works in angular | Text | Slides

In this video we will discuss, implementing routing in a separate routing module.


In Part 17 of Angular CLI tutorial, we implemented routing. At the moment, all the routing code is implemented in the root AppModule. However, for separation of concerns and maintainability, it is better to implement routing in a separate module and then import that routing module in the AppModule. If routing is in it's own module, it is easier to find and change routing code if required.


Moving routing code into it's own module is easy and straight forward

Step 1 : Create a new file in the 'app' folder. Name it app-routing.module.ts

Step 2 : Copy and paste the following code in it. The code is commented and self-explanatory.

// Import NgModule decorator to decorate AppRoutingModule class
import { NgModule } from '@angular/core';
// Import RouterModule and Routes type from angular router library
import { RouterModule, Routes } from '@angular/router';

// Import the following 3 components as we will reference
// them in the route definitions below
import { HomeComponent } from './home/home.component';
import { EmployeesComponent } from './employees/employees.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

// Configure the routes. The Routes type and the
// referenced components are imported above
const appRoutes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'employees', component: EmployeesComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: '**', component: PageNotFoundComponent }
];

// The NgModule decorator is imported above
// Pass the configured routes to the forRoot() method
// to let the angular router know about our routes
// Export the imported RouterModule so it is available
// to the module that imports this AppRoutingModule
@NgModule({
  imports: [RouterModule.forRoot(appRoutes)],
  exports: [RouterModule],
})
export class AppRoutingModule { }

Step 3 : Modify the code in the root AppModule in app.module.ts. The code is commented and self-explanatory.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { EmployeesComponent } from './employees/employees.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    EmployeesComponent,
    PageNotFoundComponent
  ],
  // Import AppRoutingModule which contains our routing code
  // AppRoutingModule has also exported angular RouterModule, so
  // all the RouterModule features are also availble to this module
  // including the <router-outlet> directive used in the AppComponent
  // If AppRoutingModule module did not export RouterModule we get
  // 'router-outlet' is not a known element error
  imports: [BrowserModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Save all changes and run the project using the following command
ng serve --open

Notice routing in our angular application works exactly the same way as before. We now have routing implemented in it's own module.

To quickly recap, here are the steps to implement routing in a separate module.

Step 1 : Set <base href> in index.html.

Step 2 : Create a separate routing module file. You can name it anything you want. I named it app-routing.module.ts.

Step 3 : Import the angular RouterModule into your application routing module (app-routing.module.ts). Also don't forget to re-export RouterModule.

Step 4 : Configure the application routes. 

Step 5 : Import the application routing module (app-routing.module.ts) in the root AppModule.

Step 6 : Specify where you want the routed component view template to be displayed using the <router-outlet> directive

Step 7 : Create a navigation menu and tie the configured routes with the menu using the routerLink directive. Optionally, use the routerLinkActive directive to style the current route that is active, so the user knows the page that he is on, in the application.

In our next video, we will discuss, how Angular CLI generates most of this routing code out of the box.

Video Link


Angular CLI generate routing module

Suggested Videos
Part 17 - Angular Routing | Text | Slides
Part 18 - How routing works in angular | Text | Slides
Part 19 - Implementing routing in separate module in angular | Text | Slides

In this video we will discuss generating routing module using the Angular CLI.


To make Angular CLI generate a routing module, all you have to do is use --routing option along with the ng new command when generating a new Angular project.
ng new RoutingDemo --routing

In our previous video, we discussed the steps to implement routing in a separate module, and them import that routing module in the application root module AppModule. Here are those steps.


Step 1 : Set <base href> in index.html.

Step 2 : Create a separate routing module file. You can name it anything you want. I named it app-routing.module.ts.

Step 3 : Import the angular RouterModule into your application routing module (app-routing.module.ts). Also don't forget to re-export RouterModule.

Step 4 : Configure the application routes. 

Step 5 : Import the application routing module (app-routing.module.ts) in the root AppModule.

Step 6 : Specify where you want the routed component view template to be displayed using the <router-outlet> directive

Step 7 : Create a navigation menu and tie the configured routes with the menu using the routerLink directive. Optionally, use the routerLinkActive directive to style the current route that is active, so the user knows the page that he is on, in the application.

Out of the above 7 steps, we only need to implement steps 4 & 7. The rest of the steps are implemented by the Angular CLI out of the box. Just imagine the amount of time we save.

Before we can implement steps 4 & 7. Let's generate the following 3 components.
Component Angular CLI Command
HomeComponent ng g c home
EmployeesComponent ng g c employees
PageNotFoundComponent ng g c pageNotFound

Now let's implement Step 4. In app-routing.module.ts file specify the application routes. Copy and paste the following code. In addition to the routes, notice we are also importing HomeComponent, EmployeesComponent & PageNotFoundComponent as we are referencing these components in the route configuration.

import { HomeComponent } from './home/home.component';
import { EmployeesComponent } from './employees/employees.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'employees', component: EmployeesComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: '**', component: PageNotFoundComponent }
];

Now let's implement Step 4. In app.component.html copy and paste the following code.

<div style="padding:5px">
    <ul class="nav nav-tabs">
        <li routerLinkActive="active">
            <a routerLink="home">Home</a>
        </li>
        <li routerLinkActive="active">
            <a routerLink="employees">Employees</a>
        </li>
    </ul>
    <br/>
    <router-outlet></router-outlet>
</div>

Finally we need to install and reference Bootstrap, to style the navigation menu. To install bootstrap execute the following npm command. We can execute this command in the command prompt window or in the integrated terminal window in Visual Studio Code.
npm install bootstrap@3 --save

Once Bootstrap is installed, open .angular-cli.json file and specify the path to the Bootstrap stylesheet in the styles property as shown below.
"styles": [
  "../node_modules/bootstrap/dist/css/bootstrap.min.css",
  "styles.css"
]

At this point stop the server. Build and run the application again using the following Angular CLI command. Routing should be working as expected.
ng serve --open

Video Link


Running angular app locally

Suggested Videos
Part 18 - How routing works in angular | Text | Slides
Part 19 - Implementing routing in separate module in angular | Text | Slides
Part 20 - Angular CLI generate routing module | Text | Slides

In this video we will discuss
  • How to compile and run an angular application locally on your development machine
  • What happens behind the scenes when we compile and run an angular application
  • What is bundling and why is it important for performance

So far in this video series we have been using the following command to build and run our angular application.
ng serve --open


Have you ever thought about what happens behind the scenes when we execute this command. Behind the scenes, Angular CLI runs Webpack to build and bundle all JavaScript and CSS code. The following are the bundles.
Bundle File What it contains
inline.bundle.js WebPack runtime. Required for WebPack to do it's job
main.bundle.js All our application code that we write
polyfills.bundle.js Browser Polyfills
styles.bundle.js Styles used by the application
vendor.bundle.js Angular and 3rd party vendor files

What is bundling and why is it important for performance
A typical real world angular application is made up of many components. Each component code is in it's own .ts file which gets transpiled to JavaScript i.e to a .js file. Along the same lines, a component may also have it's own .css file for styles. So our angular application code is in many small files. In addition to our application code files, we also have vendor code files like Angular, jQuery etc. 

Web browsers have a limit on how many scripts or CSS files they can download simultaneously. 

Because of this browser limitation, your application may suffer from performance perspective, if it has many JavaScript and CSS files to download. 

Bundling can solve this problem by combining many small application and library files into a few bundles. As mentioned before, Angular CLI runs WebPack for building and bundling angular applications.

There are several ways to see these generated bundles.
1. If you have executed the "ng serve --open" command in a command prompt window, upon build completion you can see the generated bundles in the command prompt window as shown in the image below.
angular build bundles

2. If you have executed the "ng serve --open" command in Visual Studio Code Integrated Terminal, upon build completion you can see the generated bundles in the integrated terminal window as shown in the image below.
what does ng serve do

3. "ng serve --open" command builds and runs the application. By default the application runs at port number 4200. You can change this default port number if you want to. We will discuss how to do that in our upcoming videos. When the application is served in the browser you can see the generated bundles on the "Elements" tab in Browser Developer Tools.
angular cli ng serve

4. You can also see these bundles on the "Sources" tab in Browser Developer Tools.
run angular app locally

5. To see the bundles along with their sizes click on the Network tab. If you don't see the bundles, refresh the browser window by pressing F5.
angular bundle js files

In addition to bundling, we can also use other optimisation techniques like Ahead-of-Time (AOT) Compilation, Minification, Uglification and TreeShaking to improve performance. We will discuss all these techniques and how to implement them in our upcoming videos.

The ng serve command builds and serves the application from memory for a faster development experience. It does not write the build artefacts to the disk, so we cannot use this command if you want to deploy the build to another server. For example, if you want to deploy your angular application to a test server for testing, or to your production server we cannot use ng serve. We instead use ng build. This command writes the build artefacts to the specified output folder, so the application can be deployed elsewhere. We will discuss ng build in our upcoming videos.

To customise the in-memory builds that the "ng serve" command produces, there are several options that we can use along with this command. We will discuss these options in our next video.

Video Link


Angular cli ng serve options

Suggested Videos
Part 19 - Implementing routing in separate module in angular | Text | Slides
Part 20 - Angular CLI generate routing module | Text | Slides
Part 21 - Running angular app locally | Text | Slides

In this video we will discuss some of the common options that we can use with ng serve command.


To see the list of all options that we can use with "ng serve" command use --help option
ng serve --help

The following page also shows all the options that can be used with ng serve
https://github.com/angular/angular-cli/wiki/serve


The following command, builds and launches the application in your default browser.
ng serve --open

Many of our channel subscribers have sent me emails saying their application is using Internet Explorer, but they want to use Google chrome instead. So thier question is how to change my default browser. Well that's simple and it really depends on the operating system you have. For example, on a Windows 7 operatin system here are the steps to change your default browser.
  1. Click on the Windows Start Button and in the "Search programs and files" text box type: Control
  2. Control Panel would appear in the list. Click on it.
  3. In the "Control Panel" window, click on "Default Programs"
  4. In the "Default Programs" window, click on "Set your default programs"
  5. In the list of programs that appear, select the "Browser" that you want to be the default browser and then click on the link that says "Set this program as default"
That's it. At this point, execute "ng serve --open" command and you will have your application launched in your specified default browser.

Instead of using the full option name --open, you can also use it's alias -o

The following table shows the common options, alias, default value & their purpose
Option Alias Default Purpose
--watch -w true Run build when files change
--live-reload -lr true Whether to reload the page on change
--open -o false Opens the url in default browser
--port -p 4200 The port on which the server is listening
--extract-css -ec Extract css from global styles onto css files instead of js ones

Video Link


Compile angular app

Suggested Videos
Part 20 - Angular CLI generate routing module | Text | Slides
Part 21 - Running angular app locally | Text | Slides
Part 22 - Angular cli ng serve options | Text | Slides

In this video we will discuss compiling angular applications. Along the way we will discuss producing builds both for development and production use. We will also discuss the differences between ng serve and ng build commands.


In Parts 21 and 22 of Angular CLI tutorial we discussed ng serve command. This command builds and serves the application from memory for faster development experience. ng serve command does not write the build files to the disk, so we cannot use it for deploying our application on a different server. For example, if we want to deploy our application to a test, staging or production server we cannot use ng serve command. For this we use a different command and that is ng build command.


When we execute ng build command it creates a folder with name "dist" and copies all the build files into that folder. Now the question that comes to our mind is, why is the folder named "dist". The folder is named "dist" because that is what is specified as the output directory for the build in the Angular CLI configuration file. Notice the "outDir" property is set to "dist".

By default the ng build command does a development build, not a production build. The development build is not optimised for production use. The development build is typically used for testing. With a development build it is easier to debug as the development build contains source map files.

ng build command on my machine produced the following files in the "dist" folder
ng build development

As you can see in the "dist" folder we have 
1. The favicon
2. Glyphicon files
3. Our host page index.html
4. Bundle files and their corresponding source map files

Please note : Both the following commands are equivalent and does the same thing, i.e they produce a development build
ng build or ng build --dev

If you want to deploy the application to a server, copy the contents of the "dist" folder to a folder on the server. We will discuss deployment in detail in a later video.

The bundle files (inline, main, polyfills,styles, & vendor) generated by the development build are not optimised, meaning the bundles are not minified or treeshaked to remove the code that is not being used. A production build on the other hand will have all the performance optimisation techniques like Ahead-of-time (AOT) compilation, minification, uglification and treeshaking implemented. So the sizes of the bundles that the production build produces will be significantly less than the sizes of the bundles that a dev build produces. 

To do a production build use --prod option with the ng build command. ng build command with --prod option on my machine produced the following files in the "dist" folder. 
angular production build
  1. Notice the file sizes in the production build are significantly less than the file sizes in the development build. 
  2. With the production build, by default, we do not get the source map files because we usually do not need them on a production server. 
  3. Also notice, Production build extracts css from global styles into a css file instead of js ones.
In addition to these 3 differences between a dev build and a production build, there are several other differences as well. We will discuss them in detail in our next video.

ng serve vs ng build

ng serve
  • Compiles and serves the application from memory
  • Does not write the build files to the disk
  • Typically used to run the application on local development machine
  • Cannot be used for deploying the build to another server (Ex. Testing, Staging or Production server)
ng build
  • Compiles the application to the "dist" folder
  • Can be used to produce both development & production builds
  • Typically used to deploy the application on another server
Video Link


Angular dev build vs prod build

Suggested Videos
Part 20 - Angular CLI generate routing module | Text | Slides
Part 21 - Running angular app locally | Text | Slides
Part 22 - Angular cli ng serve options | Text | Slides

In this video we will discuss the differences between a development build and a production build in angular.


To generate a development build we can use either 
ng build 
OR
ng build --dev

To generate a production build we use 
ng build --prod


Here are some of the differences between a development build and a production build in angular.

Source Maps : Development build generate Source Maps where as production build does not. 

What are Source Maps
To improve the performance, the application's JavaScript and CSS files are combined and compressed. It is extremely difficult to debug those compressed files. A source map holds information about the original files and can be used to map the code within a compressed file back to it’s original position in a source file. So with the help of these source maps we can easily debug our applications even after the the files are compressed and combined.

By default, a development build produce source maps where as a production build does not. However, we can change this default behaviour by using --sourcemaps option along with the ng build command. It's alias is -sm.

The following command produces a development build without source maps as we have set -sm option to false
ng build --dev -sm false

On the other hand, if you want source maps along with your production build set -sm option to true as shown below.
ng build --prod -sm true

Extracts CSS : With the development build global styles are extracted to .js files where as with the production build they are extracted to .css files. To change this default behaviour use --extract-css option or it's alias -ec with the ng build command.

The following command produces a development build with global styles extracted to .css file(s) instead of .js ones.
ng build --dev -ec true

Minification & Uglification : A Prod Build is both minified and uglified, where as a Dev Build is not.

What is Minification 
The process of removing excess whitespace, comments, and optional tokens like curly brackets and semicolons is called Minification. 

What is Uglification
The process of transforming code to use short variable and function names is called uglification.

The minified and uglified version of the file is smaller in size than the full version, resulting in faster response times and lower bandwidth costs.

If you look at the bundles generated by the prod build, you will notice that they are minified and uglified. Notice, extra whitespaces, comments, and optional tokens like curly brackets and semicolons are removed. Also notice, the code is transformed by using short variable and function names. On the other hand, the bundles generated by the dev build, are not minified and uglified.

Tree Shaking : A Prod build is Tree Shaked, where as a Dev build is not.

What is Tree Shaking
Tree shaking is the process of removing any code that we are not actually using in our application from the final bundle. It's one of the most effective techniques to reduce the application size.

If you look at the bundles generated by the production build, they are significantly less in size compared with the bundles generated by the development build. This is beacause with the production build the code is tree shaked to remove dead code i.e the code that is not referenced by the application.

Ahead-of-Time (AOT) Compilation : With a production build we get AOT (Ahead-of-Time) compilation, i.e the Angular component templates are pre-compiled, where as with a development build they are not. We will discuss Ahead-of-Time compilation in detail in our next video.

The following table summarises the differences between a development build and a production build
Feature Development Build Production Build
Source Maps Yes No
Extracts CSS .js file .css file
Minifaction No Yes
Uglification No Yes
Tree Shaking No Yes
AOT No Yes

Video Link


Angular AOT vs JIT

Suggested Videos
Part 22 - Angular cli ng serve options | Text | Slides
Part 23 - Compile angular app | Text | Slides
Part 24 - Angular dev build vs prod build | Text | Slides

In this video we will discuss Ahead-of-Time compilation and Just-in-Time compilation in Angular.


In Angular we have 2 models of compilation
  • JIT - Just-in-Time Compilation : JIT compilation as the name implies, compiles the application Just-in-Time in the browser at runtime.
  • AOT - Ahead-of-Time Compilation : AOT compilation compiles the application at build time.

By default, with the development build we get JIT compilation. This is how it works. The application code along with the angular compiler is downloaded by the browser. At run-time, when a request is issued to the application, the JIT-compiler in the browser compiles the application code before it is executed. This means our user who made that first request has to wait for the application to compile first.

In our previous videos we have seen that, when we build our angular application, the following JavaScript bundles are generated.
  1. Inline
  2. Main
  3. Polyfills
  4. Styles
  5. Vendor
The vendor bundle contains the compiler along with the angular framework. The compiler code is roughly half of the Angular framework.

There is a tool called source-map-explorer that we can use to inspect the JavaScript bundles. This tool analyzes the source map generated with the bundle and draws a map of all dependencies.

To be able to use this tool we have to install it first. To install this tool, execute the following command
npm install source-map-explorer --save-dev

Once we have the tool installed, if you have not done the development build yet, do the development build using the following command.
ng build

Once the build is complete, you will have the JavaScript bundles along with the source map files. Now execute the following command. 
node_modules\.bin\source-map-explorer dist\vendor.bundle.js

The above command runs the source-map-explorer against the vendor bundle and we see the graph of it as shown below. Notice the angular compiler is around 45% percent of the bundle size. As this is development build and not optimised, notice the total size of the bundle is 2.19 MB.
angular aot vs jit

With AOT compilation the angular application is pre-compiled. So this means the browser loads executable code so it can render the application immediately, without waiting to compile the application first. 

This also mean with AOT, as the application is already pre-compiled, there is also no need for the browser to download the Angular compiler. As we already know, the compiler code is roughly half of the Angular framework, so omitting it dramatically reduces the application size.

By default, the production build is Ahead-of-Time compiled. So there is no need to bundle up the angular compiler code in the vendor bundle. This brings down the vendor bundle size by almost 50%. In addition it is also minified, uglified and tree-shaked to remove any code that we are not referencing in our application. So the bundler size is further reduced.

Now, execute the following command to generate a production build. Notice I have also turned on sourcemap option. Without the sourcemap we will not be able to use the source-map-explorer tool.
ng build --prod --sourcemap true

Once the production build is complete, execute the following command. Vendor bundle name in your production build may be slightly different. Change it accordingly and execute the command.
node_modules\.bin\source-map-explorer dist\vendor.7e385ef294695236ffd1.bundle.js

Here is the graph produced by the above command. Notice now, we do not have the compiler in the bundle. The bundle size is just 313 KB.
angular production build

The AOT compiler also detects and reports template binding errors at build time itself. Let us understand this with an example.

Include the following function HomeComponent class in home.component.ts file
getText(): string {
  return 'Hello Pragim';
}

In home.component.html include the following <div> element. Notice I have deliberately mis-spelled the getText() function name.
<div [innerText]='getTex()'>

Save changes, and execute the following command. This command does a development build in-memory. At the moment we are not using AOT, so we will not know about the template binding error that is introduced above. Notice at build time we do not see any errors.
ng serve

Now launch your default browser and navigate to http://localhost:4200. We see the "home works" message as expected. However, we do not see the message returned by getText() function. This is because we deliberately mis-spelled the getText() function name. We will see this error in the browser developer tools. So this proves that, with JIT compilation we will only come to know about the template binding errors at runtime.

With AOT compilation, template binding errors are detected and reported at build time itself as apposed to runtime. To prove this, execute the following command. Notice we are using --aot option for pre-compiling our in-memory build.
ng serve --aot

The build completes with the following error. So this proves that, with AOT compilation, template binding errors are detected and reported at build time itself as apposed to runtime
angular aot error

By default, the following 2 commands use JIT compilation 
ng build
ng serve

With either of these command we can use --aot option to turn on Ahead-of-Time compilation
ng build --aot
ng serve --aot

The production build uses AOT by default. If you want to turn off AOT for the production build, you can do so by setting --aot option to false as shown below.
ng build --prod --aot false

At this point, we cannot use source-map-explorer to check if the angular compiler is in the vendor bundle because we do not have sourcemap files. If you want to inspect the bundles make sure you also turn on sourcemaps.

Video Link


Deploy angular app to IIS

Suggested Videos
Part 23 - Compile angular app | Text | Slides
Part 24 - Angular dev build vs prod build | Text | Slides
Part 25 - Angular AOT vs JIT | Text | Slides

In this video we will discuss deploying angular application to IIS.


Here are the steps

Step 1 : Build your angular application. 

If you want to deploy a development build do a development build using the following Angular CLI command. The base-href option on the build command sets the base-href element in index.html to "/ePortal/" instaed of "/". In the IIS server, we will create an application with name "ePortal" in just a bit.
ng build --base-href /ePortal/


If you want to deploy a production build do a production build using the following Angular CLI command. 
ng build --prod --base-href /ePortal/

In our case let's deploy a production build. After the build is complete, you will notice a folder with name "dist" in your Angular project folder. This folder contains all the build files. These build files need to be copied to a folder on the server where we have IIS installed.

Step 2 : Create a folder on the server where you have IIS installed. You can name the folder anything you want. I am going to name the folder "ProductionBuild" and I am creating it in C:\ drive.

Step 3 : Now copy all the contents of the "dist" folder into "ProductionBuild" folder

Step 4 : Open IIS. There are several ways to do this. One way is to type "inetmgr" in the "Run" window and click "OK"

Step 5 : Create an application in IIS. Name it "ePortal". This name has to match the value we have specified for the --base-href option in Step 1. 
  • Exapand the root IIS node
  • Expand Sites
  • Right click on "Default Web Site" and select "Add Application" from the context menu
  • In the "Alias" textbox, type "ePortal"
  • Set the "Physical Path" to folder that contains the build files. In our case it is "ProductionBuild" folder in C:\ drive
deploy angular app to iis

At this point, if you launch the browser and navigate to http://localhost/ePortal/home, you will see the "home works" message as expected. When you click on the "Employees" tab it also works as expected.

angularjs 2 refresh page 404

However, when you "Refresh" the page by pressing F5, you will see the following HTTP 404 error

angularjs 2 browser refresh not working

Step 6 :  To fix this Page Refresh issue in Angular, include the following URL rewrite rule in you web.config file. This web.config file should be in copied the "ProductionBuild" folder where we have the rest of the build files.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="AngularJS Routes" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
          </conditions>
          <action type="Rewrite" url="/ePortal" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Please note : You may also point the IIS application directly to the "dist" folder in RoutingDemo project folder. The downside of this is every time you rebuild your application, the "dist" folder is deleted and recreated.  This means you will loose the web.config file and you have to create it again.

Video Link